From b8d319a2fcac4b3e0a9b377a12b0fb029f155a2b Mon Sep 17 00:00:00 2001 From: rakshasa Date: Fri, 22 Oct 2010 11:31:11 +0000 Subject: [PATCH] * Fixed a race condition where the releasing of the global lock before calling polling would cause problems. Now a thread that acquires the global lock and wants to remove or change fd's from the main thread. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1182 e378c898-3ddf-0310-93e7-cc216c733640 --- src/core/download_list.cc | 6 ++++-- src/core/poll_manager_epoll.cc | 4 ++++ src/core/poll_manager_kqueue.cc | 4 ++++ src/core/poll_manager_select.cc | 4 ++++ src/globals.h | 2 +- src/rpc/scgi.cc | 4 +++- src/signal_handler.h | 2 +- src/thread_base.cc | 10 ++++++++++ src/thread_base.h | 3 +++ 9 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/core/download_list.cc b/src/core/download_list.cc index 8be42488..15764b7f 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -579,10 +579,12 @@ DownloadList::confirm_finished(Download* download) { rpc::call_command("d.connection_current.set", rpc::call_command_void("d.connection_seed", rpc::make_target(download)), rpc::make_target(download)); download->set_priority(download->priority()); - if (rpc::call_command_value("d.peers_min", rpc::make_target(download)) == rpc::call_command_value("throttle.min_peers.normal") && rpc::call_command_value("throttle.min_peers.seed") >= 0) + if (rpc::call_command_value("d.peers_min", rpc::make_target(download)) == rpc::call_command_value("throttle.min_peers.normal") && + rpc::call_command_value("throttle.min_peers.seed") >= 0) rpc::call_command("d.peers_min.set", rpc::call_command_void("throttle.min_peers.seed"), rpc::make_target(download)); - if (rpc::call_command_value("d.peers_max", rpc::make_target(download)) == rpc::call_command_value("throttle.max_peers.normal") && rpc::call_command_value("throttle.max_peers.seed") >= 0) + if (rpc::call_command_value("d.peers_max", rpc::make_target(download)) == rpc::call_command_value("throttle.max_peers.normal") && + rpc::call_command_value("throttle.max_peers.seed") >= 0) rpc::call_command("d.peers_max.set", rpc::call_command_void("throttle.max_peers.seed"), rpc::make_target(download)); // Do this before the slots are called in case one of them closes diff --git a/src/core/poll_manager_epoll.cc b/src/core/poll_manager_epoll.cc index b0043b3d..56b48456 100644 --- a/src/core/poll_manager_epoll.cc +++ b/src/core/poll_manager_epoll.cc @@ -69,7 +69,11 @@ PollManagerEPoll::poll(rak::timer timeout) { timeout = std::min(timeout, rak::timer(torrent::next_timeout())) + 1000; ThreadBase::release_global_lock(); + ThreadBase::entering_main_polling(); + int status = static_cast(m_poll)->poll((timeout.usec() + 999) / 1000); + + ThreadBase::leaving_main_polling(); ThreadBase::acquire_global_lock(); if (status == -1) diff --git a/src/core/poll_manager_kqueue.cc b/src/core/poll_manager_kqueue.cc index e61fa2fd..bfbfa27c 100644 --- a/src/core/poll_manager_kqueue.cc +++ b/src/core/poll_manager_kqueue.cc @@ -70,7 +70,11 @@ PollManagerKQueue::poll(rak::timer timeout) { timeout = std::min(timeout, rak::timer(torrent::next_timeout())) + 1000; ThreadBase::release_global_lock(); + ThreadBase::entering_main_polling(); + int status = static_cast(m_poll)->poll((timeout.usec() + 999) / 1000); + + ThreadBase::leaving_main_polling(); ThreadBase::acquire_global_lock(); if (status == -1) diff --git a/src/core/poll_manager_select.cc b/src/core/poll_manager_select.cc index 297c45fe..3710bc03 100644 --- a/src/core/poll_manager_select.cc +++ b/src/core/poll_manager_select.cc @@ -92,8 +92,12 @@ PollManagerSelect::poll(rak::timer timeout) { timeval t = timeout.tval(); + ThreadBase::entering_main_polling(); ThreadBase::release_global_lock(); + int status = select(maxFd + 1, m_readSet, m_writeSet, m_errorSet, &t); + + ThreadBase::leaving_main_polling(); ThreadBase::acquire_global_lock(); if (status == -1) diff --git a/src/globals.h b/src/globals.h index 240af6d8..d5b55247 100644 --- a/src/globals.h +++ b/src/globals.h @@ -54,7 +54,7 @@ class Control; extern rak::priority_queue_default taskScheduler; extern rak::timer cachedTime; -extern Control* control; +extern Control* control; // extern __thread ThreadBase* main_thread; // Only use for worker threads for now. extern ThreadMain* main_thread; extern ThreadWorker* worker_thread; diff --git a/src/rpc/scgi.cc b/src/rpc/scgi.cc index 19bc2dee..d023fb5c 100644 --- a/src/rpc/scgi.cc +++ b/src/rpc/scgi.cc @@ -165,8 +165,10 @@ SCgi::receive_call(SCgiTask* task, const char* buffer, uint32_t length) { slotWrite.set(rak::mem_fn(task, &SCgiTask::receive_write)); ThreadBase::acquire_global_lock(); - // bool result = m_slotProcess(buffer, length, slotWrite); + ThreadBase::interrupt_main_polling(); + bool result = xmlrpc.process(buffer, length, slotWrite); + ThreadBase::release_global_lock(); return result; diff --git a/src/signal_handler.h b/src/signal_handler.h index c882f544..00cd6976 100644 --- a/src/signal_handler.h +++ b/src/signal_handler.h @@ -55,7 +55,7 @@ public: private: static void caught(int signum); - static Slot m_handlers[HIGHEST_SIGNAL]; + static Slot m_handlers[HIGHEST_SIGNAL]; }; #endif diff --git a/src/thread_base.cc b/src/thread_base.cc index 64ff2331..4b11d8b2 100644 --- a/src/thread_base.cc +++ b/src/thread_base.cc @@ -196,3 +196,13 @@ ThreadBase::queue_item(thread_base_func newFunc) { if (m_state == STATE_ACTIVE) pthread_kill(m_thread, SIGUSR1); } + +void +ThreadBase::interrupt_main_polling() { + do { + if (!ThreadBase::is_main_polling()) + return; + + pthread_kill(main_thread->m_thread, SIGUSR1); + } while (1); +} diff --git a/src/thread_base.h b/src/thread_base.h index f21aa0c9..04d5dfe6 100644 --- a/src/thread_base.h +++ b/src/thread_base.h @@ -84,6 +84,9 @@ public: static void* event_loop(ThreadBase* threadBase); + // Move to libtorrent some day. + static void interrupt_main_polling(); + protected: inline rak::timer client_next_timeout();