From dc2f24344c4d2865d6523383ed493d3578fabac1 Mon Sep 17 00:00:00 2001 From: Marcos Pinto Date: Sat, 17 Nov 2007 12:22:22 +0000 Subject: [PATCH] asio sync --- libtorrent/include/libtorrent/asio/buffer.hpp | 7 +- .../asio/deadline_timer_service.hpp | 3 +- .../asio/detail/dev_poll_reactor.hpp | 110 +++++---- .../libtorrent/asio/detail/epoll_reactor.hpp | 12 +- .../libtorrent/asio/detail/kqueue_reactor.hpp | 20 +- .../asio/detail/pipe_select_interrupter.hpp | 3 +- .../libtorrent/asio/detail/posix_event.hpp | 3 +- .../libtorrent/asio/detail/posix_mutex.hpp | 9 +- .../libtorrent/asio/detail/posix_thread.hpp | 3 +- .../libtorrent/asio/detail/posix_tss_ptr.hpp | 3 +- .../asio/detail/reactive_socket_service.hpp | 8 +- .../libtorrent/asio/detail/socket_ops.hpp | 170 +++++++++++-- .../libtorrent/asio/detail/socket_types.hpp | 4 +- .../include/libtorrent/asio/detail/thread.hpp | 10 +- .../libtorrent/asio/detail/timer_queue.hpp | 25 +- .../libtorrent/asio/detail/win_event.hpp | 2 +- .../asio/detail/win_iocp_io_service.hpp | 231 +++++++++++++++++- .../asio/detail/win_iocp_io_service_fwd.hpp | 2 + .../asio/detail/win_iocp_socket_service.hpp | 34 +-- .../libtorrent/asio/detail/win_mutex.hpp | 6 +- .../libtorrent/asio/detail/win_thread.hpp | 6 +- .../libtorrent/asio/detail/win_tss_ptr.hpp | 10 +- .../libtorrent/asio/detail/wince_thread.hpp | 124 ++++++++++ .../libtorrent/asio/detail/winsock_init.hpp | 2 +- libtorrent/include/libtorrent/asio/error.hpp | 19 +- .../include/libtorrent/asio/error_code.hpp | 12 +- .../libtorrent/asio/impl/error_code.ipp | 6 +- .../include/libtorrent/asio/impl/read.ipp | 20 +- .../include/libtorrent/asio/impl/write.ipp | 18 +- .../asio/ip/detail/socket_option.hpp | 17 +- .../asio/ssl/detail/openssl_operation.hpp | 2 +- libtorrent/src/lsd.cpp | 2 +- libtorrent/src/session_impl.cpp | 2 + 33 files changed, 712 insertions(+), 193 deletions(-) create mode 100644 libtorrent/include/libtorrent/asio/detail/wince_thread.hpp diff --git a/libtorrent/include/libtorrent/asio/buffer.hpp b/libtorrent/include/libtorrent/asio/buffer.hpp index 9fe76178c..881bc1176 100644 --- a/libtorrent/include/libtorrent/asio/buffer.hpp +++ b/libtorrent/include/libtorrent/asio/buffer.hpp @@ -27,7 +27,7 @@ #include "asio/detail/pop_options.hpp" #if defined(BOOST_MSVC) -# if defined(_HAS_ITERATOR_DEBUGGING) +# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0) # if !defined(ASIO_DISABLE_BUFFER_DEBUGGING) # define ASIO_ENABLE_BUFFER_DEBUGGING # endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING) @@ -390,6 +390,11 @@ public: { } + ~buffer_debug_check() + { + iter_ = Iterator(); + } + void operator()() { *iter_; diff --git a/libtorrent/include/libtorrent/asio/deadline_timer_service.hpp b/libtorrent/include/libtorrent/asio/deadline_timer_service.hpp index 00688b3bd..e1d1bc97e 100644 --- a/libtorrent/include/libtorrent/asio/deadline_timer_service.hpp +++ b/libtorrent/include/libtorrent/asio/deadline_timer_service.hpp @@ -29,6 +29,7 @@ #include "asio/detail/kqueue_reactor.hpp" #include "asio/detail/select_reactor.hpp" #include "asio/detail/service_base.hpp" +#include "asio/detail/win_iocp_io_service.hpp" namespace asio { @@ -62,7 +63,7 @@ private: // The type of the platform-specific implementation. #if defined(ASIO_HAS_IOCP) typedef detail::deadline_timer_service< - traits_type, detail::select_reactor > service_impl_type; + traits_type, detail::win_iocp_io_service> service_impl_type; #elif defined(ASIO_HAS_EPOLL) typedef detail::deadline_timer_service< traits_type, detail::epoll_reactor > service_impl_type; diff --git a/libtorrent/include/libtorrent/asio/detail/dev_poll_reactor.hpp b/libtorrent/include/libtorrent/asio/detail/dev_poll_reactor.hpp index bc18b5bc9..15babcdb9 100644 --- a/libtorrent/include/libtorrent/asio/detail/dev_poll_reactor.hpp +++ b/libtorrent/include/libtorrent/asio/detail/dev_poll_reactor.hpp @@ -140,22 +140,13 @@ public: if (read_op_queue_.enqueue_operation(descriptor, handler)) { - ::pollfd ev = { 0 }; - ev.fd = descriptor; + ::pollfd& ev = add_pending_event_change(descriptor); ev.events = POLLIN | POLLERR | POLLHUP; if (write_op_queue_.has_operation(descriptor)) ev.events |= POLLOUT; if (except_op_queue_.has_operation(descriptor)) ev.events |= POLLPRI; - ev.revents = 0; - - int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); - if (result != sizeof(ev)) - { - asio::error_code ec(errno, - asio::error::system_category); - read_op_queue_.dispatch_all_operations(descriptor, ec); - } + interrupter_.interrupt(); } } @@ -175,22 +166,13 @@ public: if (write_op_queue_.enqueue_operation(descriptor, handler)) { - ::pollfd ev = { 0 }; - ev.fd = descriptor; + ::pollfd& ev = add_pending_event_change(descriptor); ev.events = POLLOUT | POLLERR | POLLHUP; if (read_op_queue_.has_operation(descriptor)) ev.events |= POLLIN; if (except_op_queue_.has_operation(descriptor)) ev.events |= POLLPRI; - ev.revents = 0; - - int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); - if (result != sizeof(ev)) - { - asio::error_code ec(errno, - asio::error::system_category); - write_op_queue_.dispatch_all_operations(descriptor, ec); - } + interrupter_.interrupt(); } } @@ -206,22 +188,13 @@ public: if (except_op_queue_.enqueue_operation(descriptor, handler)) { - ::pollfd ev = { 0 }; - ev.fd = descriptor; + ::pollfd& ev = add_pending_event_change(descriptor); ev.events = POLLPRI | POLLERR | POLLHUP; if (read_op_queue_.has_operation(descriptor)) ev.events |= POLLIN; if (write_op_queue_.has_operation(descriptor)) ev.events |= POLLOUT; - ev.revents = 0; - - int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); - if (result != sizeof(ev)) - { - asio::error_code ec(errno, - asio::error::system_category); - except_op_queue_.dispatch_all_operations(descriptor, ec); - } + interrupter_.interrupt(); } } @@ -241,21 +214,11 @@ public: && need_mod; if (need_mod) { - ::pollfd ev = { 0 }; - ev.fd = descriptor; + ::pollfd& ev = add_pending_event_change(descriptor); ev.events = POLLOUT | POLLPRI | POLLERR | POLLHUP; if (read_op_queue_.has_operation(descriptor)) ev.events |= POLLIN; - ev.revents = 0; - - int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); - if (result != sizeof(ev)) - { - asio::error_code ec(errno, - asio::error::system_category); - write_op_queue_.dispatch_all_operations(descriptor, ec); - except_op_queue_.dispatch_all_operations(descriptor, ec); - } + interrupter_.interrupt(); } } @@ -285,11 +248,9 @@ public: asio::detail::mutex::scoped_lock lock(mutex_); // Remove the descriptor from /dev/poll. - ::pollfd ev = { 0 }; - ev.fd = descriptor; + ::pollfd& ev = add_pending_event_change(descriptor); ev.events = POLLREMOVE; - ev.revents = 0; - ::write(dev_poll_fd_, &ev, sizeof(ev)); + interrupter_.interrupt(); // Cancel any outstanding operations associated with the descriptor. cancel_ops_unlocked(descriptor); @@ -374,6 +335,26 @@ private: return; } + // Write the pending event registration changes to the /dev/poll descriptor. + std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); + errno = 0; + int result = ::write(dev_poll_fd_, + &pending_event_changes_[0], events_size); + if (result != static_cast(events_size)) + { + for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) + { + int descriptor = pending_event_changes_[i].fd; + asio::error_code ec = asio::error_code( + errno, asio::error::get_system_category()); + read_op_queue_.dispatch_all_operations(descriptor, ec); + write_op_queue_.dispatch_all_operations(descriptor, ec); + except_op_queue_.dispatch_all_operations(descriptor, ec); + } + } + pending_event_changes_.clear(); + pending_event_change_index_.clear(); + int timeout = block ? get_timeout() : 0; wait_in_progress_ = true; lock.unlock(); @@ -454,7 +435,7 @@ private: if (result != sizeof(ev)) { ec = asio::error_code(errno, - asio::error::system_category); + asio::error::get_system_category()); read_op_queue_.dispatch_all_operations(descriptor, ec); write_op_queue_.dispatch_all_operations(descriptor, ec); except_op_queue_.dispatch_all_operations(descriptor, ec); @@ -513,7 +494,7 @@ private: boost::throw_exception( asio::system_error( asio::error_code(errno, - asio::error::system_category), + asio::error::get_system_category()), "/dev/poll")); } return fd; @@ -588,12 +569,39 @@ private: timer_queues_for_cleanup_[i]->cleanup_timers(); } + // Add a pending event entry for the given descriptor. + ::pollfd& add_pending_event_change(int descriptor) + { + hash_map::iterator iter + = pending_event_change_index_.find(descriptor); + if (iter == pending_event_change_index_.end()) + { + std::size_t index = pending_event_changes_.size(); + pending_event_changes_.reserve(pending_event_changes_.size() + 1); + pending_event_change_index_.insert(std::make_pair(descriptor, index)); + pending_event_changes_.push_back(::pollfd()); + pending_event_changes_[index].fd = descriptor; + pending_event_changes_[index].revents = 0; + return pending_event_changes_[index]; + } + else + { + return pending_event_changes_[iter->second]; + } + } + // Mutex to protect access to internal data. asio::detail::mutex mutex_; // The /dev/poll file descriptor. int dev_poll_fd_; + // Vector of /dev/poll events waiting to be written to the descriptor. + std::vector< ::pollfd> pending_event_changes_; + + // Hash map to associate a descriptor with a pending event change index. + hash_map pending_event_change_index_; + // Whether the DP_POLL operation is currently in progress bool wait_in_progress_; diff --git a/libtorrent/include/libtorrent/asio/detail/epoll_reactor.hpp b/libtorrent/include/libtorrent/asio/detail/epoll_reactor.hpp index 7f3cf7b90..93d39a23c 100644 --- a/libtorrent/include/libtorrent/asio/detail/epoll_reactor.hpp +++ b/libtorrent/include/libtorrent/asio/detail/epoll_reactor.hpp @@ -160,7 +160,7 @@ public: if (result != 0) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); read_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -196,7 +196,7 @@ public: if (result != 0) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -228,7 +228,7 @@ public: if (result != 0) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); except_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -262,7 +262,7 @@ public: if (result != 0) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, ec); except_op_queue_.dispatch_all_operations(descriptor, ec); } @@ -456,7 +456,7 @@ private: if (result != 0) { ec = asio::error_code(errno, - asio::error::system_category); + asio::error::get_system_category()); read_op_queue_.dispatch_all_operations(descriptor, ec); write_op_queue_.dispatch_all_operations(descriptor, ec); except_op_queue_.dispatch_all_operations(descriptor, ec); @@ -518,7 +518,7 @@ private: boost::throw_exception( asio::system_error( asio::error_code(errno, - asio::error::system_category), + asio::error::get_system_category()), "epoll")); } return fd; diff --git a/libtorrent/include/libtorrent/asio/detail/kqueue_reactor.hpp b/libtorrent/include/libtorrent/asio/detail/kqueue_reactor.hpp index 5fffc6788..896ff5403 100644 --- a/libtorrent/include/libtorrent/asio/detail/kqueue_reactor.hpp +++ b/libtorrent/include/libtorrent/asio/detail/kqueue_reactor.hpp @@ -151,7 +151,7 @@ public: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); read_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -178,7 +178,7 @@ public: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -204,7 +204,7 @@ public: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); except_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -228,7 +228,7 @@ public: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -243,7 +243,7 @@ public: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); except_op_queue_.dispatch_all_operations(descriptor, ec); write_op_queue_.dispatch_all_operations(descriptor, ec); } @@ -397,7 +397,7 @@ private: if (events[i].flags & EV_ERROR) { asio::error_code error( - events[i].data, asio::error::system_category); + events[i].data, asio::error::get_system_category()); except_op_queue_.dispatch_all_operations(descriptor, error); read_op_queue_.dispatch_all_operations(descriptor, error); } @@ -428,7 +428,7 @@ private: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code error(errno, - asio::error::system_category); + asio::error::get_system_category()); except_op_queue_.dispatch_all_operations(descriptor, error); read_op_queue_.dispatch_all_operations(descriptor, error); } @@ -440,7 +440,7 @@ private: if (events[i].flags & EV_ERROR) { asio::error_code error( - events[i].data, asio::error::system_category); + events[i].data, asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, error); } else @@ -458,7 +458,7 @@ private: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code error(errno, - asio::error::system_category); + asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, error); } } @@ -515,7 +515,7 @@ private: boost::throw_exception( asio::system_error( asio::error_code(errno, - asio::error::system_category), + asio::error::get_system_category()), "kqueue")); } return fd; diff --git a/libtorrent/include/libtorrent/asio/detail/pipe_select_interrupter.hpp b/libtorrent/include/libtorrent/asio/detail/pipe_select_interrupter.hpp index c85765cc3..c0ac2aab1 100644 --- a/libtorrent/include/libtorrent/asio/detail/pipe_select_interrupter.hpp +++ b/libtorrent/include/libtorrent/asio/detail/pipe_select_interrupter.hpp @@ -51,7 +51,8 @@ public: } else { - asio::error_code ec(errno, asio::error::system_category); + asio::error_code ec(errno, + asio::error::get_system_category()); asio::system_error e(ec, "pipe_select_interrupter"); boost::throw_exception(e); } diff --git a/libtorrent/include/libtorrent/asio/detail/posix_event.hpp b/libtorrent/include/libtorrent/asio/detail/posix_event.hpp index b48586f15..305ed873b 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_event.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_event.hpp @@ -48,7 +48,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "event"); boost::throw_exception(e); } diff --git a/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp b/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp index 6067880fb..c2a01d0b0 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp @@ -51,7 +51,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "mutex"); boost::throw_exception(e); } @@ -70,7 +71,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "mutex"); boost::throw_exception(e); } @@ -83,7 +85,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "mutex"); boost::throw_exception(e); } diff --git a/libtorrent/include/libtorrent/asio/detail/posix_thread.hpp b/libtorrent/include/libtorrent/asio/detail/posix_thread.hpp index 6e5815426..a4a3da23c 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_thread.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_thread.hpp @@ -53,7 +53,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "thread"); boost::throw_exception(e); } diff --git a/libtorrent/include/libtorrent/asio/detail/posix_tss_ptr.hpp b/libtorrent/include/libtorrent/asio/detail/posix_tss_ptr.hpp index dda329c40..1becb8dc4 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_tss_ptr.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_tss_ptr.hpp @@ -47,7 +47,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "tss"); boost::throw_exception(e); } diff --git a/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp b/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp index 0d272c578..df70f8863 100644 --- a/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp @@ -157,7 +157,8 @@ public: if (int err = reactor_.register_descriptor(sock.get())) { - ec = asio::error_code(err, asio::error::system_category); + ec = asio::error_code(err, + asio::error::get_system_category()); return ec; } @@ -181,7 +182,8 @@ public: if (int err = reactor_.register_descriptor(native_socket)) { - ec = asio::error_code(err, asio::error::system_category); + ec = asio::error_code(err, + asio::error::get_system_category()); return ec; } @@ -1489,7 +1491,7 @@ public: if (connect_error) { ec = asio::error_code(connect_error, - asio::error::system_category); + asio::error::get_system_category()); io_service_.post(bind_handler(handler_, ec)); return true; } diff --git a/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp b/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp index 92826d89e..ee0b4b582 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp @@ -48,10 +48,11 @@ extern "C" unsigned int if_nametoindex(const char*); inline void clear_error(asio::error_code& ec) { - errno = 0; #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) WSASetLastError(0); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#else + errno = 0; +#endif ec = asio::error_code(); } @@ -61,9 +62,10 @@ inline ReturnType error_wrapper(ReturnType return_value, { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) ec = asio::error_code(WSAGetLastError(), - asio::error::system_category); + asio::error::get_system_category()); #else - ec = asio::error_code(errno, asio::error::system_category); + ec = asio::error_code(errno, + asio::error::get_system_category()); #endif return return_value; } @@ -100,6 +102,10 @@ inline socket_type accept(socket_type s, socket_addr_type* addr, } #endif +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + clear_error(ec); +#endif + return new_s; } @@ -114,14 +120,25 @@ inline int bind(socket_type s, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(call_bind(&msghdr::msg_namelen, s, addr, addrlen), ec); + int result = error_wrapper(call_bind( + &msghdr::msg_namelen, s, addr, addrlen), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } inline int close(socket_type s, asio::error_code& ec) { clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return error_wrapper(::closesocket(s), ec); + int result = error_wrapper(::closesocket(s), ec); +# if defined(UNDER_CE) + if (result == 0) + clear_error(ec); +# endif + return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) return error_wrapper(::close(s), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -130,7 +147,12 @@ inline int close(socket_type s, asio::error_code& ec) inline int shutdown(socket_type s, int what, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::shutdown(s, what), ec); + int result = error_wrapper(::shutdown(s, what), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } template @@ -144,14 +166,24 @@ inline int connect(socket_type s, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(call_connect( + int result = error_wrapper(call_connect( &msghdr::msg_namelen, s, addr, addrlen), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } inline int listen(socket_type s, int backlog, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::listen(s, backlog), ec); + int result = error_wrapper(::listen(s, backlog), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -217,6 +249,9 @@ inline int recv(socket_type s, buf* bufs, size_t count, int flags, recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); if (result != 0) return -1; +# if defined(UNDER_CE) + clear_error(ec); +# endif return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -242,6 +277,9 @@ inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, *addrlen = (std::size_t)tmp_addrlen; if (result != 0) return -1; +# if defined(UNDER_CE) + clear_error(ec); +# endif return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -268,6 +306,9 @@ inline int send(socket_type s, const buf* bufs, size_t count, int flags, send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); if (result != 0) return -1; +# if defined(UNDER_CE) + clear_error(ec); +# endif return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -290,9 +331,13 @@ inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, DWORD send_buf_count = static_cast(count); DWORD bytes_transferred = 0; int result = error_wrapper(::WSASendTo(s, const_cast(bufs), - send_buf_count, &bytes_transferred, flags, addr, addrlen, 0, 0), ec); + send_buf_count, &bytes_transferred, flags, addr, + static_cast(addrlen), 0, 0), ec); if (result != 0) return -1; +# if defined(UNDER_CE) + clear_error(ec); +# endif return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -327,6 +372,10 @@ inline socket_type socket(int af, int type, int protocol, reinterpret_cast(&optval), sizeof(optval)); } +# if defined(UNDER_CE) + clear_error(ec); +# endif + return s; #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) socket_type s = error_wrapper(::socket(af, type, protocol), ec); @@ -385,8 +434,13 @@ inline int setsockopt(socket_type s, int level, int optname, return -1; #else // defined(__BORLANDC__) clear_error(ec); - return error_wrapper(call_setsockopt(&msghdr::msg_namelen, + int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, s, level, optname, optval, optlen), ec); +# if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +# endif + return result; #endif // defined(__BORLANDC__) } @@ -455,6 +509,10 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval, *static_cast(optval) = 1; clear_error(ec); } +# if defined(UNDER_CE) + if (result == 0) + clear_error(ec); +# endif return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) clear_error(ec); @@ -490,8 +548,13 @@ inline int getpeername(socket_type s, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(call_getpeername( + int result = error_wrapper(call_getpeername( &msghdr::msg_namelen, s, addr, addrlen), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } template @@ -508,8 +571,13 @@ inline int getsockname(socket_type s, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(call_getsockname( + int result = error_wrapper(call_getsockname( &msghdr::msg_namelen, s, addr, addrlen), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, @@ -517,7 +585,12 @@ inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, { clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return error_wrapper(::ioctlsocket(s, cmd, arg), ec); + int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); +# if defined(UNDER_CE) + if (result == 0) + clear_error(ec); +# endif + return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) return error_wrapper(::ioctl(s, cmd, arg), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -556,8 +629,13 @@ inline int select(int nfds, fd_set* readfds, fd_set* writefds, return error_wrapper(::pselect(nfds, readfds, writefds, exceptfds, timeout ? &ts : 0, 0), ec); #else - return error_wrapper(::select(nfds, readfds, + int result = error_wrapper(::select(nfds, readfds, writefds, exceptfds, timeout), ec); +# if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result >= 0) + clear_error(ec); +# endif + return result; #endif } @@ -568,7 +646,12 @@ inline int poll_read(socket_type s, asio::error_code& ec) FD_ZERO(&fds); FD_SET(s, &fds); clear_error(ec); - return error_wrapper(::select(s, &fds, 0, 0, 0), ec); + int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); +# if defined(UNDER_CE) + if (result >= 0) + clear_error(ec); +# endif + return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) pollfd fds; fds.fd = s; @@ -586,7 +669,12 @@ inline int poll_write(socket_type s, asio::error_code& ec) FD_ZERO(&fds); FD_SET(s, &fds); clear_error(ec); - return error_wrapper(::select(s, 0, &fds, 0, 0), ec); + int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); +# if defined(UNDER_CE) + if (result >= 0) + clear_error(ec); +# endif + return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) pollfd fds; fds.fd = s; @@ -634,9 +722,17 @@ inline const char* inet_ntop(int af, const void* src, char* dest, size_t length, } DWORD string_length = static_cast(length); +#if defined(BOOST_NO_ANSI_APIS) + LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); + int result = error_wrapper(::WSAAddressToStringW( + reinterpret_cast(&address), + address_length, 0, string_buffer, &string_length), ec); + ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); +#else int result = error_wrapper(::WSAAddressToStringA( reinterpret_cast(&address), address_length, 0, dest, &string_length), ec); +#endif // Windows may set error code on success. if (result != socket_error_retval) @@ -680,10 +776,20 @@ inline int inet_pton(int af, const char* src, void* dest, sockaddr_storage_type address; int address_length = sizeof(sockaddr_storage_type); +#if defined(BOOST_NO_ANSI_APIS) + int num_wide_chars = strlen(src) + 1; + LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); + ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); + int result = error_wrapper(::WSAStringToAddressW( + wide_buffer, af, 0, + reinterpret_cast(&address), + &address_length), ec); +#else int result = error_wrapper(::WSAStringToAddressA( const_cast(src), af, 0, reinterpret_cast(&address), &address_length), ec); +#endif if (af == AF_INET) { @@ -717,6 +823,11 @@ inline int inet_pton(int af, const char* src, void* dest, if (result == socket_error_retval && !ec) ec = asio::error::invalid_argument; +#if defined(UNDER_CE) + if (result != socket_error_retval) + clear_error(ec); +#endif + return result == socket_error_retval ? -1 : 1; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::inet_pton(af, src, dest), ec); @@ -743,7 +854,12 @@ inline int inet_pton(int af, const char* src, void* dest, inline int gethostname(char* name, int namelen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::gethostname(name, namelen), ec); + int result = error_wrapper(::gethostname(name, namelen), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ @@ -782,6 +898,9 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af, hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); if (!retval) return 0; +# if defined(UNDER_CE) + clear_error(ec); +# endif *result = *retval; return retval; #elif defined(__sun) || defined(__QNX__) @@ -830,6 +949,9 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, hostent* retval = error_wrapper(::gethostbyname(name), ec); if (!retval) return 0; +# if defined(UNDER_CE) + clear_error(ec); +# endif *result = *retval; return result; #elif defined(__sun) || defined(__QNX__) @@ -1601,10 +1723,10 @@ inline asio::error_code translate_addrinfo_error(int error) default: // Possibly the non-portable EAI_SYSTEM. #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) return asio::error_code( - WSAGetLastError(), asio::error::system_category); + WSAGetLastError(), asio::error::get_system_category()); #else return asio::error_code( - errno, asio::error::system_category); + errno, asio::error::get_system_category()); #endif } } @@ -1615,7 +1737,7 @@ inline asio::error_code getaddrinfo(const char* host, { clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) // Building for Windows XP, Windows Server 2003, or later. int error = ::getaddrinfo(host, service, hints, result); return ec = translate_addrinfo_error(error); @@ -1646,7 +1768,7 @@ inline asio::error_code getaddrinfo(const char* host, inline void freeaddrinfo(addrinfo_type* ai) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) // Building for Windows XP, Windows Server 2003, or later. ::freeaddrinfo(ai); # else @@ -1674,7 +1796,7 @@ inline asio::error_code getnameinfo(const socket_addr_type* addr, char* serv, std::size_t servlen, int flags, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) // Building for Windows XP, Windows Server 2003, or later. clear_error(ec); int error = ::getnameinfo(addr, addrlen, host, static_cast(hostlen), @@ -1737,8 +1859,6 @@ inline u_short_type host_to_network_short(u_short_type value) } // namespace detail } // namespace asio -#undef ASIO_SOCKET_CALL - #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_SOCKET_OPS_HPP diff --git a/libtorrent/include/libtorrent/asio/detail/socket_types.hpp b/libtorrent/include/libtorrent/asio/detail/socket_types.hpp index f16bba747..e2b68910c 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_types.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_types.hpp @@ -80,7 +80,9 @@ # undef ASIO_WSPIAPI_H_DEFINED # endif // defined(ASIO_WSPIAPI_H_DEFINED) # if !defined(ASIO_NO_DEFAULT_LINKED_LIBS) -# if defined(_MSC_VER) || defined(__BORLANDC__) +# if defined(UNDER_CE) +# pragma comment(lib, "ws2.lib") +# elif defined(_MSC_VER) || defined(__BORLANDC__) # pragma comment(lib, "ws2_32.lib") # pragma comment(lib, "mswsock.lib") # endif // defined(_MSC_VER) || defined(__BORLANDC__) diff --git a/libtorrent/include/libtorrent/asio/detail/thread.hpp b/libtorrent/include/libtorrent/asio/detail/thread.hpp index b334c38af..520477e37 100644 --- a/libtorrent/include/libtorrent/asio/detail/thread.hpp +++ b/libtorrent/include/libtorrent/asio/detail/thread.hpp @@ -24,7 +24,11 @@ #if !defined(BOOST_HAS_THREADS) # include "asio/detail/null_thread.hpp" #elif defined(BOOST_WINDOWS) -# include "asio/detail/win_thread.hpp" +# if defined(UNDER_CE) +# include "asio/detail/wince_thread.hpp" +# else +# include "asio/detail/win_thread.hpp" +# endif #elif defined(BOOST_HAS_PTHREADS) # include "asio/detail/posix_thread.hpp" #else @@ -37,7 +41,11 @@ namespace detail { #if !defined(BOOST_HAS_THREADS) typedef null_thread thread; #elif defined(BOOST_WINDOWS) +# if defined(UNDER_CE) +typedef wince_thread thread; +# else typedef win_thread thread; +# endif #elif defined(BOOST_HAS_PTHREADS) typedef posix_thread thread; #endif diff --git a/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp b/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp index 7735e87cf..472cc3759 100644 --- a/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp +++ b/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp @@ -162,13 +162,7 @@ public: // Destroy timers that are waiting to be cleaned up. virtual void cleanup_timers() { - while (cleanup_timers_) - { - timer_base* next_timer = cleanup_timers_->next_; - cleanup_timers_->next_ = 0; - cleanup_timers_->destroy(); - cleanup_timers_ = next_timer; - } + destroy_timer_list(cleanup_timers_); } // Destroy all timers. @@ -181,11 +175,12 @@ public: timer_base* t = i->second; typename hash_map::iterator old_i = i++; timers_.erase(old_i); - t->destroy(); + destroy_timer_list(t); } heap_.clear(); timers_.clear(); - cleanup_timers(); + destroy_timer_list(cancelled_timers_); + destroy_timer_list(cleanup_timers_); } private: @@ -367,6 +362,18 @@ private: } } + // Destroy all timers in a linked list. + void destroy_timer_list(timer_base*& t) + { + while (t) + { + timer_base* next = t->next_; + t->next_ = 0; + t->destroy(); + t = next; + } + } + // A hash of timer token to linked lists of timers. hash_map timers_; diff --git a/libtorrent/include/libtorrent/asio/detail/win_event.hpp b/libtorrent/include/libtorrent/asio/detail/win_event.hpp index c73ed56ea..ff97fbedc 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_event.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_event.hpp @@ -49,7 +49,7 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "event"); boost::throw_exception(e); } diff --git a/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service.hpp b/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service.hpp index 61eeb1745..46e651653 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service.hpp @@ -33,7 +33,9 @@ #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/service_base.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue.hpp" #include "asio/detail/win_iocp_operation.hpp" +#include "asio/detail/mutex.hpp" namespace asio { namespace detail { @@ -51,7 +53,9 @@ public: iocp_(), outstanding_work_(0), stopped_(0), - shutdown_(0) + shutdown_(0), + timer_thread_(0), + timer_interrupt_issued_(false) { } @@ -64,7 +68,7 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "iocp"); boost::throw_exception(e); } @@ -93,6 +97,10 @@ public: if (overlapped) static_cast(overlapped)->destroy(); } + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->destroy_timers(); + timer_queues_.clear(); } // Register a handle with the IO completion port. @@ -175,7 +183,7 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "pqcs"); boost::throw_exception(e); } @@ -231,7 +239,7 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "pqcs"); boost::throw_exception(e); } @@ -251,20 +259,102 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "pqcs"); boost::throw_exception(e); } } + // Add a new timer queue to the service. + template + void add_timer_queue(timer_queue& timer_queue) + { + asio::detail::mutex::scoped_lock lock(timer_mutex_); + timer_queues_.push_back(&timer_queue); + } + + // Remove a timer queue from the service. + template + void remove_timer_queue(timer_queue& timer_queue) + { + asio::detail::mutex::scoped_lock lock(timer_mutex_); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + if (timer_queues_[i] == &timer_queue) + { + timer_queues_.erase(timer_queues_.begin() + i); + return; + } + } + } + + // Schedule a timer in the given timer queue to expire at the specified + // absolute time. The handler object will be invoked when the timer expires. + template + void schedule_timer(timer_queue& timer_queue, + const typename Time_Traits::time_type& time, Handler handler, void* token) + { + // If the service has been shut down we silently discard the timer. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return; + + asio::detail::mutex::scoped_lock lock(timer_mutex_); + if (timer_queue.enqueue_timer(time, handler, token)) + { + if (!timer_interrupt_issued_) + { + timer_interrupt_issued_ = true; + lock.unlock(); + ::PostQueuedCompletionStatus(iocp_.handle, + 0, steal_timer_dispatching, 0); + } + } + } + + // Cancel the timer associated with the given token. Returns the number of + // handlers that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& timer_queue, void* token) + { + // If the service has been shut down we silently ignore the cancellation. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return 0; + + asio::detail::mutex::scoped_lock lock(timer_mutex_); + std::size_t n = timer_queue.cancel_timer(token); + if (n > 0 && !timer_interrupt_issued_) + { + timer_interrupt_issued_ = true; + lock.unlock(); + ::PostQueuedCompletionStatus(iocp_.handle, + 0, steal_timer_dispatching, 0); + } + return n; + } + private: // Dequeues at most one operation from the I/O completion port, and then // executes it. Returns the number of operations that were dequeued (i.e. // either 0 or 1). size_t do_one(bool block, asio::error_code& ec) { + long this_thread_id = static_cast(::GetCurrentThreadId()); + for (;;) { + // Try to acquire responsibility for dispatching timers. + bool dispatching_timers = (::InterlockedCompareExchange( + &timer_thread_, this_thread_id, 0) == 0); + + // Calculate timeout for GetQueuedCompletionStatus call. + DWORD timeout = max_timeout; + if (dispatching_timers) + { + asio::detail::mutex::scoped_lock lock(timer_mutex_); + timer_interrupt_issued_ = false; + timeout = get_timeout(); + } + // Get the next operation from the queue. DWORD bytes_transferred = 0; #if (WINVER < 0x0500) @@ -275,18 +365,47 @@ private: LPOVERLAPPED overlapped = 0; ::SetLastError(0); BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, block ? 1000 : 0); + &completion_key, &overlapped, block ? timeout : 0); DWORD last_error = ::GetLastError(); + // Dispatch any pending timers. + if (dispatching_timers) + { + asio::detail::mutex::scoped_lock lock(timer_mutex_); + timer_queues_copy_ = timer_queues_; + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + timer_queues_[i]->dispatch_timers(); + timer_queues_[i]->dispatch_cancellations(); + timer_queues_[i]->cleanup_timers(); + } + } + if (!ok && overlapped == 0) { if (block && last_error == WAIT_TIMEOUT) + { + // Relinquish responsibility for dispatching timers. + if (dispatching_timers) + { + ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); + } + continue; + } + + // Transfer responsibility for dispatching timers to another thread. + if (dispatching_timers && ::InterlockedCompareExchange( + &timer_thread_, 0, this_thread_id) == this_thread_id) + { + ::PostQueuedCompletionStatus(iocp_.handle, + 0, transfer_timer_dispatching, 0); + } + ec = asio::error_code(); return 0; } - - if (overlapped) + else if (overlapped) { // We may have been passed a last_error value in the completion_key. if (last_error == 0) @@ -294,6 +413,14 @@ private: last_error = completion_key; } + // Transfer responsibility for dispatching timers to another thread. + if (dispatching_timers && ::InterlockedCompareExchange( + &timer_thread_, 0, this_thread_id) == this_thread_id) + { + ::PostQueuedCompletionStatus(iocp_.handle, + 0, transfer_timer_dispatching, 0); + } + // Ensure that the io_service does not exit due to running out of work // while we make the upcall. auto_work work(*this); @@ -305,18 +432,34 @@ private: ec = asio::error_code(); return 1; } + else if (completion_key == transfer_timer_dispatching) + { + // Woken up to try to acquire responsibility for dispatching timers. + ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); + } + else if (completion_key == steal_timer_dispatching) + { + // Woken up to steal responsibility for dispatching timers. + ::InterlockedExchange(&timer_thread_, 0); + } else { // The stopped_ flag is always checked to ensure that any leftover // interrupts from a previous run invocation are ignored. if (::InterlockedExchangeAdd(&stopped_, 0) != 0) { + // Relinquish responsibility for dispatching timers. + if (dispatching_timers) + { + ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); + } + // Wake up next thread that is blocked on GetQueuedCompletionStatus. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); return 0; } @@ -327,6 +470,45 @@ private: } } + // Check if all timer queues are empty. + bool all_timer_queues_are_empty() const + { + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + if (!timer_queues_[i]->empty()) + return false; + return true; + } + + // Get the timeout value for the GetQueuedCompletionStatus call. The timeout + // value is returned as a number of milliseconds. We will wait no longer than + // 1000 milliseconds. + DWORD get_timeout() + { + if (all_timer_queues_are_empty()) + return max_timeout; + + boost::posix_time::time_duration minimum_wait_duration + = boost::posix_time::milliseconds(max_timeout); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + boost::posix_time::time_duration wait_duration + = timer_queues_[i]->wait_duration(); + if (wait_duration < minimum_wait_duration) + minimum_wait_duration = wait_duration; + } + + if (minimum_wait_duration > boost::posix_time::time_duration()) + { + int milliseconds = minimum_wait_duration.total_milliseconds(); + return static_cast(milliseconds > 0 ? milliseconds : 1); + } + else + { + return 0; + } + } + struct auto_work { auto_work(win_iocp_io_service& io_service) @@ -416,6 +598,37 @@ private: // Flag to indicate whether the service has been shut down. long shutdown_; + + enum + { + // Maximum GetQueuedCompletionStatus timeout, in milliseconds. + max_timeout = 1000, + + // Completion key value to indicate that responsibility for dispatching + // timers is being cooperatively transferred from one thread to another. + transfer_timer_dispatching = 1, + + // Completion key value to indicate that responsibility for dispatching + // timers should be stolen from another thread. + steal_timer_dispatching = 2 + }; + + // The thread that's currently in charge of dispatching timers. + long timer_thread_; + + // Mutex for protecting access to the timer queues. + mutex timer_mutex_; + + // Whether a thread has been interrupted to process a new timeout. + bool timer_interrupt_issued_; + + // The timer queues. + std::vector timer_queues_; + + // A copy of the timer queues, used when dispatching, cancelling and cleaning + // up timers. The copy is stored as a class data member to avoid unnecessary + // memory allocation. + std::vector timer_queues_copy_; }; } // namespace detail diff --git a/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service_fwd.hpp b/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service_fwd.hpp index 26eacae2a..b3d1dec34 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service_fwd.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service_fwd.hpp @@ -27,6 +27,7 @@ #if !defined(ASIO_DISABLE_IOCP) #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +#if !defined(UNDER_CE) // Define this to indicate that IOCP is supported on the target platform. #define ASIO_HAS_IOCP 1 @@ -39,6 +40,7 @@ class win_iocp_io_service; } // namespace detail } // namespace asio +#endif // !defined(UNDER_CE) #endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #endif // !defined(ASIO_DISABLE_IOCP) diff --git a/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp b/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp index 2b6ee80e8..cb3640638 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp @@ -338,7 +338,7 @@ public: { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); } else { @@ -360,7 +360,7 @@ public: { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); } else { @@ -667,7 +667,7 @@ public: else if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); return 0; } @@ -719,7 +719,7 @@ public: // Map non-portable errors to their portable counterparts. asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) @@ -822,7 +822,7 @@ public: asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -867,7 +867,7 @@ public: if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); return 0; } @@ -917,7 +917,7 @@ public: // Map non-portable errors to their portable counterparts. asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; @@ -1001,7 +1001,7 @@ public: asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1056,7 +1056,7 @@ public: else if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); return 0; } if (bytes_transferred == 0) @@ -1115,7 +1115,7 @@ public: // Map non-portable errors to their portable counterparts. asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) @@ -1223,7 +1223,7 @@ public: asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1270,7 +1270,7 @@ public: if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); return 0; } if (bytes_transferred == 0) @@ -1337,7 +1337,7 @@ public: // Map non-portable errors to their portable counterparts. asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; @@ -1432,7 +1432,7 @@ public: asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1671,7 +1671,7 @@ public: // Call the handler. asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); asio_handler_invoke_helpers::invoke( detail::bind_handler(handler, ec), &handler); } @@ -1772,7 +1772,7 @@ public: asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec)); } } @@ -1849,7 +1849,7 @@ public: if (connect_error) { ec = asio::error_code(connect_error, - asio::error::system_category); + asio::error::get_system_category()); io_service_.post(bind_handler(handler_, ec)); return true; } diff --git a/libtorrent/include/libtorrent/asio/detail/win_mutex.hpp b/libtorrent/include/libtorrent/asio/detail/win_mutex.hpp index 4d1bc20c2..f937db69f 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_mutex.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_mutex.hpp @@ -49,7 +49,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "mutex"); boost::throw_exception(e); } @@ -68,7 +69,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "mutex"); boost::throw_exception(e); } diff --git a/libtorrent/include/libtorrent/asio/detail/win_thread.hpp b/libtorrent/include/libtorrent/asio/detail/win_thread.hpp index c6bd61af5..4a80d15a3 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_thread.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_thread.hpp @@ -21,7 +21,7 @@ #include #include "asio/detail/pop_options.hpp" -#if defined(BOOST_WINDOWS) +#if defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include "asio/error.hpp" #include "asio/system_error.hpp" @@ -56,7 +56,7 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "thread"); boost::throw_exception(e); } @@ -118,7 +118,7 @@ inline unsigned int __stdcall win_thread_function(void* arg) } // namespace detail } // namespace asio -#endif // defined(BOOST_WINDOWS) +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include "asio/detail/pop_options.hpp" diff --git a/libtorrent/include/libtorrent/asio/detail/win_tss_ptr.hpp b/libtorrent/include/libtorrent/asio/detail/win_tss_ptr.hpp index d84810d41..8f6eaf6cb 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_tss_ptr.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_tss_ptr.hpp @@ -40,16 +40,22 @@ class win_tss_ptr : private noncopyable { public: +#if defined(UNDER_CE) + enum { out_of_indexes = 0xFFFFFFFF }; +#else + enum { out_of_indexes = TLS_OUT_OF_INDEXES }; +#endif + // Constructor. win_tss_ptr() { tss_key_ = ::TlsAlloc(); - if (tss_key_ == TLS_OUT_OF_INDEXES) + if (tss_key_ == out_of_indexes) { DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "tss"); boost::throw_exception(e); } diff --git a/libtorrent/include/libtorrent/asio/detail/wince_thread.hpp b/libtorrent/include/libtorrent/asio/detail/wince_thread.hpp new file mode 100644 index 000000000..f65a36f0c --- /dev/null +++ b/libtorrent/include/libtorrent/asio/detail/wince_thread.hpp @@ -0,0 +1,124 @@ +// +// wince_thread.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_WINCE_THREAD_HPP +#define ASIO_DETAIL_WINCE_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include "asio/detail/pop_options.hpp" + +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + +#include "asio/error.hpp" +#include "asio/system_error.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include +#include "asio/detail/pop_options.hpp" + +namespace asio { +namespace detail { + +DWORD WINAPI wince_thread_function(LPVOID arg); + +class wince_thread + : private noncopyable +{ +public: + // Constructor. + template + wince_thread(Function f) + { + std::auto_ptr arg(new func(f)); + DWORD thread_id = 0; + thread_ = ::CreateThread(0, 0, wince_thread_function, + arg.get(), 0, &thread_id); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + asio::system_error e( + asio::error_code(last_error, + asio::error::get_system_category()), + "thread"); + boost::throw_exception(e); + } + arg.release(); + } + + // Destructor. + ~wince_thread() + { + ::CloseHandle(thread_); + } + + // Wait for the thread to exit. + void join() + { + ::WaitForSingleObject(thread_, INFINITE); + } + +private: + friend DWORD WINAPI wince_thread_function(LPVOID arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ::HANDLE thread_; +}; + +inline DWORD WINAPI wince_thread_function(LPVOID arg) +{ + std::auto_ptr func( + static_cast(arg)); + func->run(); + return 0; +} + +} // namespace detail +} // namespace asio + +#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WINCE_THREAD_HPP diff --git a/libtorrent/include/libtorrent/asio/detail/winsock_init.hpp b/libtorrent/include/libtorrent/asio/detail/winsock_init.hpp index cdebed72f..65efb8852 100644 --- a/libtorrent/include/libtorrent/asio/detail/winsock_init.hpp +++ b/libtorrent/include/libtorrent/asio/detail/winsock_init.hpp @@ -87,7 +87,7 @@ public: { asio::system_error e( asio::error_code(ref_->result(), - asio::error::system_category), + asio::error::get_system_category()), "winsock"); boost::throw_exception(e); } diff --git a/libtorrent/include/libtorrent/asio/error.hpp b/libtorrent/include/libtorrent/asio/error.hpp index 9cc7818e8..c65599c91 100644 --- a/libtorrent/include/libtorrent/asio/error.hpp +++ b/libtorrent/include/libtorrent/asio/error.hpp @@ -61,7 +61,7 @@ enum basic_errors /// Address family not supported by protocol. address_family_not_supported = ASIO_SOCKET_ERROR(EAFNOSUPPORT), - /// Port already in use. + /// Address already in use. address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE), /// Transport endpoint is already connected. @@ -82,7 +82,7 @@ enum basic_errors /// Bad file descriptor. bad_descriptor = ASIO_SOCKET_ERROR(EBADF), - /// Bad port. + /// Bad address. fault = ASIO_SOCKET_ERROR(EFAULT), /// No route to host. @@ -205,27 +205,32 @@ enum ssl_errors inline asio::error_code make_error_code(basic_errors e) { - return asio::error_code(static_cast(e), system_category); + return asio::error_code( + static_cast(e), get_system_category()); } inline asio::error_code make_error_code(netdb_errors e) { - return asio::error_code(static_cast(e), netdb_category); + return asio::error_code( + static_cast(e), get_netdb_category()); } inline asio::error_code make_error_code(addrinfo_errors e) { - return asio::error_code(static_cast(e), addrinfo_category); + return asio::error_code( + static_cast(e), get_addrinfo_category()); } inline asio::error_code make_error_code(misc_errors e) { - return asio::error_code(static_cast(e), misc_category); + return asio::error_code( + static_cast(e), get_misc_category()); } inline asio::error_code make_error_code(ssl_errors e) { - return asio::error_code(static_cast(e), ssl_category); + return asio::error_code( + static_cast(e), get_ssl_category()); } } // namespace error diff --git a/libtorrent/include/libtorrent/asio/error_code.hpp b/libtorrent/include/libtorrent/asio/error_code.hpp index db3f453e0..989898ce5 100644 --- a/libtorrent/include/libtorrent/asio/error_code.hpp +++ b/libtorrent/include/libtorrent/asio/error_code.hpp @@ -41,10 +41,10 @@ namespace error system_category = ASIO_WIN_OR_POSIX(0, 0), /// Error codes from NetDB functions. - netdb_category = ASIO_WIN_OR_POSIX(system_category, 1), + netdb_category = ASIO_WIN_OR_POSIX(_system_category, 1), /// Error codes from getaddrinfo. - addrinfo_category = ASIO_WIN_OR_POSIX(system_category, 2), + addrinfo_category = ASIO_WIN_OR_POSIX(_system_category, 2), /// Miscellaneous error codes. misc_category = ASIO_WIN_OR_POSIX(3, 3), @@ -52,6 +52,14 @@ namespace error /// SSL error codes. ssl_category = ASIO_WIN_OR_POSIX(4, 4) }; + + // Category getters. + inline error_category get_system_category() { return system_category; } + inline error_category get_netdb_category() { return netdb_category; } + inline error_category get_addrinfo_category() { return addrinfo_category; } + inline error_category get_misc_category() { return misc_category; } + inline error_category get_ssl_category() { return ssl_category; } + } // namespace error /// Bring error category type into the asio namespace. diff --git a/libtorrent/include/libtorrent/asio/impl/error_code.ipp b/libtorrent/include/libtorrent/asio/impl/error_code.ipp index aaef231eb..9925cb484 100644 --- a/libtorrent/include/libtorrent/asio/impl/error_code.ipp +++ b/libtorrent/include/libtorrent/asio/impl/error_code.ipp @@ -35,11 +35,11 @@ inline std::string error_code::message() const return "Already open."; if (*this == error::not_found) return "Not found."; - if (category_ == error::ssl_category) + if (category_ == error::get_ssl_category()) return "SSL error."; #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) value_type value = value_; - if (category() != error::system_category && *this != error::eof) + if (category() != error::get_system_category() && *this != error::eof) return "asio error"; if (*this == error::eof) value = ERROR_HANDLE_EOF; @@ -78,7 +78,7 @@ inline std::string error_code::message() const return "Service not found."; if (*this == error::socket_type_not_supported) return "Socket type not supported."; - if (category() != error::system_category) + if (category() != error::get_system_category()) return "asio error"; #if defined(__sun) || defined(__QNX__) return strerror(value_); diff --git a/libtorrent/include/libtorrent/asio/impl/read.ipp b/libtorrent/include/libtorrent/asio/impl/read.ipp index 53a92b734..f30f50fb0 100644 --- a/libtorrent/include/libtorrent/asio/impl/read.ipp +++ b/libtorrent/include/libtorrent/asio/impl/read.ipp @@ -19,7 +19,6 @@ #include "asio/detail/push_options.hpp" #include -#include #include "asio/detail/pop_options.hpp" #include "asio/buffer.hpp" @@ -139,25 +138,23 @@ namespace detail std::size_t bytes_transferred) { total_transferred_ += bytes_transferred; - buffers_->consume(bytes_transferred); - if ((*completion_condition_)(ec, total_transferred_) - || buffers_->begin() == buffers_->end()) + buffers_.consume(bytes_transferred); + if (completion_condition_(ec, total_transferred_) + || buffers_.begin() == buffers_.end()) { - buffers_.reset(); - completion_condition_.reset(); handler_(ec, total_transferred_); } else { - stream_.async_read_some(*buffers_, *this); + stream_.async_read_some(buffers_, *this); } } //private: AsyncReadStream& stream_; - boost::optional buffers_; + buffers_type buffers_; std::size_t total_transferred_; - boost::optional completion_condition_; + CompletionCondition completion_condition_; ReadHandler handler_; }; @@ -238,9 +235,8 @@ namespace detail total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); if (streambuf_.size() == streambuf_.max_size() - || (*completion_condition_)(ec, total_transferred_)) + || completion_condition_(ec, total_transferred_)) { - completion_condition_.reset(); handler_(ec, total_transferred_); } else @@ -255,7 +251,7 @@ namespace detail AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; std::size_t total_transferred_; - boost::optional completion_condition_; + CompletionCondition completion_condition_; ReadHandler handler_; }; diff --git a/libtorrent/include/libtorrent/asio/impl/write.ipp b/libtorrent/include/libtorrent/asio/impl/write.ipp index c8d221e12..8c2d1d33f 100644 --- a/libtorrent/include/libtorrent/asio/impl/write.ipp +++ b/libtorrent/include/libtorrent/asio/impl/write.ipp @@ -17,10 +17,6 @@ #include "asio/detail/push_options.hpp" -#include "asio/detail/push_options.hpp" -#include -#include "asio/detail/pop_options.hpp" - #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" #include "asio/detail/bind_handler.hpp" @@ -128,25 +124,23 @@ namespace detail std::size_t bytes_transferred) { total_transferred_ += bytes_transferred; - buffers_->consume(bytes_transferred); - if ((*completion_condition_)(ec, total_transferred_) - || buffers_->begin() == buffers_->end()) + buffers_.consume(bytes_transferred); + if (completion_condition_(ec, total_transferred_) + || buffers_.begin() == buffers_.end()) { - buffers_.reset(); - completion_condition_.reset(); handler_(ec, total_transferred_); } else { - stream_.async_write_some(*buffers_, *this); + stream_.async_write_some(buffers_, *this); } } //private: AsyncWriteStream& stream_; - boost::optional buffers_; + buffers_type buffers_; std::size_t total_transferred_; - boost::optional completion_condition_; + CompletionCondition completion_condition_; WriteHandler handler_; }; diff --git a/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp b/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp index f564ba2c5..1d43d6059 100644 --- a/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp +++ b/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp @@ -252,6 +252,13 @@ template class multicast_hops { public: +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + typedef int ipv4_value_type; +#else + typedef unsigned char ipv4_value_type; +#endif + typedef int ipv6_value_type; + // Default constructor. multicast_hops() : ipv4_value_(0), @@ -264,7 +271,7 @@ public: { if (v < 0 || v > 255) throw std::out_of_range("multicast hops value out of range"); - ipv4_value_ = static_cast(v); + ipv4_value_ = (ipv4_value_type)v; ipv6_value_ = v; } @@ -273,7 +280,7 @@ public: { if (v < 0 || v > 255) throw std::out_of_range("multicast hops value out of range"); - ipv4_value_ = static_cast(v); + ipv4_value_ = (ipv4_value_type)v; ipv6_value_ = v; return *this; } @@ -342,7 +349,7 @@ public: else if (ipv6_value_ > 255) ipv4_value_ = 255; else - ipv4_value_ = static_cast(ipv6_value_); + ipv4_value_ = (ipv4_value_type)ipv6_value_; } else { @@ -353,8 +360,8 @@ public: } private: - unsigned char ipv4_value_; - int ipv6_value_; + ipv4_value_type ipv4_value_; + ipv6_value_type ipv6_value_; }; // Helper template for implementing ip_mreq-based options. diff --git a/libtorrent/include/libtorrent/asio/ssl/detail/openssl_operation.hpp b/libtorrent/include/libtorrent/asio/ssl/detail/openssl_operation.hpp index 5fd3ebba4..c254aceb2 100755 --- a/libtorrent/include/libtorrent/asio/ssl/detail/openssl_operation.hpp +++ b/libtorrent/include/libtorrent/asio/ssl/detail/openssl_operation.hpp @@ -179,7 +179,7 @@ public: else { return handler_(asio::error_code( - error_code, asio::error::ssl_category), rc); + error_code, asio::error::get_ssl_category()), rc); } } diff --git a/libtorrent/src/lsd.cpp b/libtorrent/src/lsd.cpp index 6e1dcb7b3..091f8f686 100644 --- a/libtorrent/src/lsd.cpp +++ b/libtorrent/src/lsd.cpp @@ -183,7 +183,7 @@ void lsd::on_announce(udp::endpoint const& from, char* buffer void lsd::close() { - m_socket.close(); m_broadcast_timer.cancel(); + m_socket.close(); } diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index c41079fdc..3132b80c9 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -2317,6 +2317,8 @@ namespace detail void session_impl::stop_lsd() { mutex_t::scoped_lock l(m_mutex); + if (m_lsd.get()) + m_lsd->close(); m_lsd = 0; }