From ab047ce1ecb1e3c16f7975e2682461919dc5ddf5 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sun, 3 Nov 2024 20:51:49 +0000 Subject: [PATCH 1/5] stuff --- src/torrent/utils/signal_bitfield.cc | 25 ++++++------ src/torrent/utils/signal_bitfield.h | 59 ++++++---------------------- 2 files changed, 26 insertions(+), 58 deletions(-) diff --git a/src/torrent/utils/signal_bitfield.cc b/src/torrent/utils/signal_bitfield.cc index dfc3d1feb..805e46f4c 100644 --- a/src/torrent/utils/signal_bitfield.cc +++ b/src/torrent/utils/signal_bitfield.cc @@ -1,9 +1,10 @@ #include "config.h" -#include "torrent/exceptions.h" - #include "signal_bitfield.h" +#include +#include "torrent/exceptions.h" + namespace torrent { const unsigned int signal_bitfield::max_size; @@ -11,35 +12,35 @@ const unsigned int signal_bitfield::max_size; // Only the thread owning this signal bitfield should add signals. unsigned int signal_bitfield::add_signal(slot_type slot) { + if (m_thread_id != std::this_thread::get_id()) + throw internal_error("signal_bitfield::add_signal(...): Only the owning thread can add signals."); + if (m_size >= max_size) throw internal_error("signal_bitfield::add_signal(...): No more available slots."); if (!slot) throw internal_error("signal_bitfield::add_signal(...): Cannot add empty slot."); - unsigned int index = m_size; - __sync_add_and_fetch(&m_size, 1); - + unsigned int index = m_size++; m_slots[index] = slot; + return index; } void signal_bitfield::work() { - bitfield_type bitfield; + // static_assert(std::atomic()::is_always_lock_free(), "signal_bitfield::work(...): Bitfield type is not lockfree."); - while (!__sync_bool_compare_and_swap(&m_bitfield, (bitfield = m_bitfield), 0)) - ; // Do nothing. + if (m_thread_id != std::this_thread::get_id()) + throw internal_error("signal_bitfield::work(...): Only the owning thread can do work for signal bitfields."); - unsigned int i = 0; + auto bitfield = m_bitfield.exchange(0); - while (bitfield) { + for (unsigned int i = 0; bitfield != 0; i++) { if ((bitfield & (1 << i))) { m_slots[i](); bitfield = bitfield & ~(1 << i); } - - i++; } } diff --git a/src/torrent/utils/signal_bitfield.h b/src/torrent/utils/signal_bitfield.h index ffa336d2c..c6e3c3104 100644 --- a/src/torrent/utils/signal_bitfield.h +++ b/src/torrent/utils/signal_bitfield.h @@ -1,70 +1,37 @@ -// libTorrent - BitTorrent library -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY +// Allows a thread to define work it will do when receiving a signal. #ifndef LIBTORRENT_UTILS_SIGNAL_BITFIELD_H #define LIBTORRENT_UTILS_SIGNAL_BITFIELD_H +#include #include +#include #include namespace torrent { -class LIBTORRENT_EXPORT lt_cacheline_aligned signal_bitfield { +class LIBTORRENT_EXPORT signal_bitfield { public: typedef uint32_t bitfield_type; typedef std::function slot_type; - + static const unsigned int max_size = 32; - signal_bitfield() : m_bitfield(0), m_size(0) {} - + signal_bitfield() : m_thread_id(std::this_thread::get_id()), m_size(0), m_bitfield(0) {} + + unsigned int add_signal(slot_type slot); bool has_signal(unsigned int index) const { return m_bitfield & (1 << index); } - // Do the interrupt from the thread? - void signal(unsigned int index) { __sync_or_and_fetch(&m_bitfield, 1 << index); } + void signal(unsigned int index) { m_bitfield |= 1 << index; } void work(); - unsigned int add_signal(slot_type slot); - private: + std::thread::id m_thread_id; + unsigned int m_size; + slot_type m_slots[max_size]; - bitfield_type m_bitfield; - unsigned int m_size; - slot_type m_slots[max_size] lt_cacheline_aligned; + std::atomic m_bitfield; }; } From 4b5a8d522ea600affbaa2ddaafbd813941ccee99 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 30 Nov 2024 09:08:59 +0000 Subject: [PATCH 2/5] Pass signal_bitfield owner thread. --- src/torrent/utils/signal_bitfield.h | 2 ++ src/torrent/utils/thread_base.cc | 19 +++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/torrent/utils/signal_bitfield.h b/src/torrent/utils/signal_bitfield.h index c6e3c3104..d8e5d7431 100644 --- a/src/torrent/utils/signal_bitfield.h +++ b/src/torrent/utils/signal_bitfield.h @@ -26,6 +26,8 @@ class LIBTORRENT_EXPORT signal_bitfield { void signal(unsigned int index) { m_bitfield |= 1 << index; } void work(); + void handover(std::thread::id thread_id) { m_thread_id = thread_id; } + private: std::thread::id m_thread_id; unsigned int m_size; diff --git a/src/torrent/utils/thread_base.cc b/src/torrent/utils/thread_base.cc index ec0619f37..faee1dc9c 100644 --- a/src/torrent/utils/thread_base.cc +++ b/src/torrent/utils/thread_base.cc @@ -4,11 +4,11 @@ #include #include -#include "exceptions.h" -#include "poll.h" -#include "thread_base.h" -#include "thread_interrupt.h" -#include "utils/log.h" +#include "torrent/exceptions.h" +#include "torrent/poll.h" +#include "torrent/utils/thread_base.h" +#include "torrent/utils/thread_interrupt.h" +#include "torrent/utils/log.h" #include "utils/instrumentation.h" namespace torrent { @@ -41,9 +41,6 @@ thread_base::~thread_base() { void thread_base::start_thread() { - if (this == nullptr) - throw internal_error("Called thread_base::start_thread on a nullptr."); - if (m_poll == nullptr) throw internal_error("No poll object for thread defined."); @@ -68,7 +65,7 @@ thread_base::stop_thread_wait() { while (!is_inactive()) { usleep(1000); - } + } acquire_global_lock(); } @@ -103,7 +100,9 @@ thread_base::event_loop(thread_base* thread) { #endif lt_log_print(torrent::LOG_THREAD_NOTICE, "%s: Starting thread.", thread->name()); - + + thread->m_signal_bitfield.handover(std::this_thread::get_id()); + try { // #ifdef USE_INTERRUPT_SOCKET From 37315af2a7ac4ca8c1cfc8262ddadbf3ecb43d04 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sat, 30 Nov 2024 10:04:59 +0000 Subject: [PATCH 3/5] Updated thread_base to use std::atomic. --- src/thread_disk.cc | 38 +------------- src/thread_main.cc | 36 ------------- src/thread_main.h | 36 ------------- src/torrent/poll_epoll.cc | 38 -------------- src/torrent/poll_kqueue.cc | 38 -------------- src/torrent/poll_select.cc | 40 +------------- src/torrent/utils/thread_base.cc | 20 ++++--- src/torrent/utils/thread_base.h | 72 +++++++------------------- test/torrent/utils/test_thread_base.cc | 1 - 9 files changed, 33 insertions(+), 286 deletions(-) diff --git a/src/thread_disk.cc b/src/thread_disk.cc index ff5b3073f..981d578c7 100644 --- a/src/thread_disk.cc +++ b/src/thread_disk.cc @@ -1,39 +1,3 @@ -// libTorrent - BitTorrent library -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - #include "config.h" #include @@ -67,7 +31,7 @@ thread_disk::call_events() { if ((m_flags & flag_did_shutdown)) throw internal_error("Already trigged shutdown."); - __sync_or_and_fetch(&m_flags, flag_did_shutdown); + m_flags |= flag_did_shutdown; throw shutdown_exception(); } diff --git a/src/thread_main.cc b/src/thread_main.cc index 018a61de2..a8e9d3157 100644 --- a/src/thread_main.cc +++ b/src/thread_main.cc @@ -1,39 +1,3 @@ -// libTorrent - BitTorrent library -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - #include "config.h" #include diff --git a/src/thread_main.h b/src/thread_main.h index da6ab1604..22ae41155 100644 --- a/src/thread_main.h +++ b/src/thread_main.h @@ -1,39 +1,3 @@ -// libTorrent - BitTorrent library -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - #ifndef LIBTORRENT_THREAD_MAIN_H #define LIBTORRENT_THREAD_MAIN_H diff --git a/src/torrent/poll_epoll.cc b/src/torrent/poll_epoll.cc index 345a7365e..5758ad2d0 100644 --- a/src/torrent/poll_epoll.cc +++ b/src/torrent/poll_epoll.cc @@ -1,39 +1,3 @@ -// libTorrent - BitTorrent library -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - #include "config.h" #include @@ -203,13 +167,11 @@ PollEPoll::do_poll(int64_t timeout_usec, int flags) { if (!(flags & poll_worker_thread)) { thread_base::release_global_lock(); - thread_base::entering_main_polling(); } int status = poll((timeout.usec() + 999) / 1000); if (!(flags & poll_worker_thread)) { - thread_base::leaving_main_polling(); thread_base::acquire_global_lock(); } diff --git a/src/torrent/poll_kqueue.cc b/src/torrent/poll_kqueue.cc index 6bd4d02da..bebe42b78 100644 --- a/src/torrent/poll_kqueue.cc +++ b/src/torrent/poll_kqueue.cc @@ -1,39 +1,3 @@ -// libTorrent - BitTorrent library -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version.213 -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - #include "config.h" #include @@ -262,13 +226,11 @@ PollKQueue::do_poll(int64_t timeout_usec, int flags) { if (!(flags & poll_worker_thread)) { thread_base::release_global_lock(); - thread_base::entering_main_polling(); } int status = poll((timeout.usec() + 999) / 1000); if (!(flags & poll_worker_thread)) { - thread_base::leaving_main_polling(); thread_base::acquire_global_lock(); } diff --git a/src/torrent/poll_select.cc b/src/torrent/poll_select.cc index dc802c3cd..4c82df1f7 100644 --- a/src/torrent/poll_select.cc +++ b/src/torrent/poll_select.cc @@ -1,39 +1,3 @@ -// libTorrent - BitTorrent library -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - #include "config.h" #include @@ -243,14 +207,12 @@ PollSelect::do_poll(int64_t timeout_usec, int flags) { timeval t = timeout.tval(); if (!(flags & poll_worker_thread)) { - thread_base::entering_main_polling(); thread_base::release_global_lock(); } int status = select(maxFd + 1, read_set, write_set, error_set, &t); if (!(flags & poll_worker_thread)) { - thread_base::leaving_main_polling(); thread_base::acquire_global_lock(); } @@ -273,7 +235,7 @@ log_poll_open(Event* event) { if (log_fd == -1) { snprintf(buffer, 256, LT_LOG_POLL_OPEN, getpid()); - + if ((log_fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC)) == -1) throw internal_error("Could not open poll open log file."); } diff --git a/src/torrent/utils/thread_base.cc b/src/torrent/utils/thread_base.cc index faee1dc9c..365d618b1 100644 --- a/src/torrent/utils/thread_base.cc +++ b/src/torrent/utils/thread_base.cc @@ -13,7 +13,7 @@ namespace torrent { -thread_base::global_lock_type lt_cacheline_aligned thread_base::m_global = { 0, 0, PTHREAD_MUTEX_INITIALIZER }; +thread_base::global_lock_type lt_cacheline_aligned thread_base::m_global = { 0, PTHREAD_MUTEX_INITIALIZER }; thread_base::thread_base() : m_state(STATE_UNKNOWN), @@ -53,7 +53,7 @@ thread_base::start_thread() { void thread_base::stop_thread() { - __sync_fetch_and_or(&m_flags, flag_do_shutdown); + m_flags |= flag_do_shutdown; interrupt(); } @@ -88,10 +88,10 @@ thread_base::event_loop(thread_base* thread) { if (thread == nullptr) throw internal_error("thread_base::event_loop called with a null pointer thread"); - if (!thread->is_initialized()) - throw internal_error("thread_base::event_loop call on an uninitialized object"); + auto previous_state = STATE_INITIALIZED; - __sync_lock_test_and_set(&thread->m_state, STATE_ACTIVE); + if (!thread->m_state.compare_exchange_strong(previous_state, STATE_ACTIVE)) + throw internal_error("thread_base::event_loop called on an object that is not in the initialized state."); #if defined(HAS_PTHREAD_SETNAME_NP_DARWIN) pthread_setname_np(thread->name()); @@ -116,7 +116,7 @@ thread_base::event_loop(thread_base* thread) { thread->call_events(); thread->signal_bitfield()->work(); - __sync_fetch_and_or(&thread->m_flags, flag_polling); + thread->m_flags |= flag_polling; // Call again after setting flag_polling to ensure we process // any events set while it was working. @@ -151,7 +151,7 @@ thread_base::event_loop(thread_base* thread) { instrumentation_update(INSTRUMENTATION_POLLING_EVENTS, event_count); instrumentation_update(instrumentation_enum(INSTRUMENTATION_POLLING_EVENTS + thread->m_instrumentation_index), event_count); - __sync_fetch_and_and(&thread->m_flags, ~(flag_polling | flag_no_timeout)); + thread->m_flags &= ~(flag_polling | flag_no_timeout); } // #ifdef USE_INTERRUPT_SOCKET @@ -162,7 +162,11 @@ thread_base::event_loop(thread_base* thread) { lt_log_print(torrent::LOG_THREAD_NOTICE, "%s: Shutting down thread.", thread->name()); } - __sync_lock_test_and_set(&thread->m_state, STATE_INACTIVE); + previous_state = STATE_ACTIVE; + + if (!thread->m_state.compare_exchange_strong(previous_state, STATE_INACTIVE)) + throw internal_error("thread_base::event_loop called on an object that is not in the active state."); + return NULL; } diff --git a/src/torrent/utils/thread_base.h b/src/torrent/utils/thread_base.h index bead96592..8706546fb 100644 --- a/src/torrent/utils/thread_base.h +++ b/src/torrent/utils/thread_base.h @@ -1,24 +1,24 @@ #ifndef LIBTORRENT_UTILS_THREAD_BASE_H #define LIBTORRENT_UTILS_THREAD_BASE_H -#import -#import -#import +#include +#include +#include +#include -#import -#import +#include +#include namespace torrent { class Poll; class thread_interrupt; -class LIBTORRENT_EXPORT lt_cacheline_aligned thread_base { +class LIBTORRENT_EXPORT thread_base { public: typedef void* (*pthread_func)(void*); typedef std::function slot_void; typedef std::function slot_timer; - typedef class signal_bitfield signal_type; enum state_type { STATE_UNKNOWN, @@ -48,13 +48,13 @@ class LIBTORRENT_EXPORT lt_cacheline_aligned thread_base { bool has_do_shutdown() const { return (flags() & flag_do_shutdown); } bool has_did_shutdown() const { return (flags() & flag_did_shutdown); } - state_type state() const; - int flags() const; + state_type state() const { return m_state; } + int flags() const { return m_flags; } virtual const char* name() const = 0; Poll* poll() { return m_poll; } - signal_type* signal_bitfield() { return &m_signal_bitfield; } + signal_bitfield* signal_bitfield() { return &m_signal_bitfield; } pthread_t pthread() { return m_thread; } virtual void init_thread() = 0; @@ -76,19 +76,14 @@ class LIBTORRENT_EXPORT lt_cacheline_aligned thread_base { static inline void release_global_lock(); static inline void waive_global_lock(); - static inline bool is_main_polling() { return m_global.main_polling; } - static inline void entering_main_polling(); - static inline void leaving_main_polling(); - static bool should_handle_sigusr1(); static void* event_loop(thread_base* thread); protected: - struct lt_cacheline_aligned global_lock_type { - int waiting; - int main_polling; - pthread_mutex_t lock; + struct global_lock_type { + int waiting; + pthread_mutex_t lock; }; virtual void call_events() = 0; @@ -96,14 +91,14 @@ class LIBTORRENT_EXPORT lt_cacheline_aligned thread_base { static global_lock_type m_global; - pthread_t m_thread; - state_type m_state lt_cacheline_aligned; - int m_flags lt_cacheline_aligned; + pthread_t m_thread; + std::atomic m_state; + std::atomic m_flags; - int m_instrumentation_index; + int m_instrumentation_index; - Poll* m_poll; - signal_type m_signal_bitfield; + Poll* m_poll; + class signal_bitfield m_signal_bitfield; slot_void m_slot_do_work; slot_timer m_slot_next_timeout; @@ -122,18 +117,6 @@ thread_base::is_current() const { return m_thread == pthread_self(); } -inline int -thread_base::flags() const { - __sync_synchronize(); - return m_flags; -} - -inline thread_base::state_type -thread_base::state() const { - __sync_synchronize(); - return m_state; -} - inline void thread_base::send_event_signal(unsigned int index, bool do_interrupt) { m_signal_bitfield.signal(index); @@ -167,23 +150,6 @@ thread_base::waive_global_lock() { acquire_global_lock(); } -// 'entering/leaving_main_polling' is used by the main polling thread -// to indicate to other threads when it is safe to change the main -// thread's event entries. -// -// A thread should first aquire global lock, then if it needs to -// change poll'ed sockets on the main thread it should call -// 'interrupt_main_polling' unless 'is_main_polling() == false'. -inline void -thread_base::entering_main_polling() { - __sync_lock_test_and_set(&thread_base::m_global.main_polling, 1); } -inline void -thread_base::leaving_main_polling() { - __sync_lock_test_and_set(&thread_base::m_global.main_polling, 0); -} - -} - #endif diff --git a/test/torrent/utils/test_thread_base.cc b/test/torrent/utils/test_thread_base.cc index 33519b7c4..8c93a851f 100644 --- a/test/torrent/utils/test_thread_base.cc +++ b/test/torrent/utils/test_thread_base.cc @@ -33,7 +33,6 @@ test_thread_base::test_basic() { CPPUNIT_ASSERT(thread->flags() == 0); - CPPUNIT_ASSERT(!thread->is_main_polling()); CPPUNIT_ASSERT(!thread->is_active()); CPPUNIT_ASSERT(thread->global_queue_size() == 0); CPPUNIT_ASSERT(thread->poll() == NULL); From cd7e9a8505743d1b3ecf3825273bb4b663996cbc Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sun, 1 Dec 2024 15:49:34 +0000 Subject: [PATCH 4/5] Minor fixes. --- src/torrent/utils/signal_bitfield.cc | 2 +- src/torrent/utils/thread_interrupt.cc | 44 +++--------------------- src/torrent/utils/thread_interrupt.h | 48 ++------------------------- 3 files changed, 9 insertions(+), 85 deletions(-) diff --git a/src/torrent/utils/signal_bitfield.cc b/src/torrent/utils/signal_bitfield.cc index 805e46f4c..99df85462 100644 --- a/src/torrent/utils/signal_bitfield.cc +++ b/src/torrent/utils/signal_bitfield.cc @@ -36,7 +36,7 @@ signal_bitfield::work() { auto bitfield = m_bitfield.exchange(0); - for (unsigned int i = 0; bitfield != 0; i++) { + for (unsigned int i = 0; bitfield != 0 && i < m_size; i++) { if ((bitfield & (1 << i))) { m_slots[i](); bitfield = bitfield & ~(1 << i); diff --git a/src/torrent/utils/thread_interrupt.cc b/src/torrent/utils/thread_interrupt.cc index 27426d9c8..0b0057518 100644 --- a/src/torrent/utils/thread_interrupt.cc +++ b/src/torrent/utils/thread_interrupt.cc @@ -1,39 +1,3 @@ -// libTorrent - BitTorrent library -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - #include "config.h" #include "thread_interrupt.h" @@ -63,7 +27,7 @@ thread_interrupt::~thread_interrupt() { bool thread_interrupt::poke() { - if (!__sync_bool_compare_and_swap(&m_other->m_poking, false, true)) + if (m_poking.test_and_set()) return true; int result = ::send(m_fileDesc, "a", 1, 0); @@ -95,6 +59,10 @@ thread_interrupt::create_pair() { void thread_interrupt::event_read() { + // This has a race condition where if poked again while processing the polled events it might be + // missed. + m_poking.clear(); + char buffer[256]; int result = ::recv(m_fileDesc, buffer, 256, 0); @@ -103,8 +71,6 @@ thread_interrupt::event_read() { throw internal_error("Invalid result reading from thread_interrupt socket."); instrumentation_update(INSTRUMENTATION_POLLING_INTERRUPT_READ_EVENT, 1); - - __sync_bool_compare_and_swap(&m_poking, true, false); } } diff --git a/src/torrent/utils/thread_interrupt.h b/src/torrent/utils/thread_interrupt.h index 0d388027b..c1748b114 100644 --- a/src/torrent/utils/thread_interrupt.h +++ b/src/torrent/utils/thread_interrupt.h @@ -1,42 +1,7 @@ -// libTorrent - BitTorrent library -// Copyright (C) 2005-2011, Jari Sundell -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// In addition, as a special exception, the copyright holders give -// permission to link the code of portions of this program with the -// OpenSSL library under certain conditions as described in each -// individual source file, and distribute linked combinations -// including the two. -// -// You must obey the GNU General Public License in all respects for -// all of the code used other than OpenSSL. If you modify file(s) -// with this exception, you may extend this exception to your version -// of the file(s), but you are not obligated to do so. If you do not -// wish to do so, delete this exception statement from your version. -// If you delete this exception statement from all source files in the -// program, then also delete it here. -// -// Contact: Jari Sundell -// -// Skomakerveien 33 -// 3185 Skoppum, NORWAY - #ifndef LIBTORRENT_UTILS_THREAD_INTERRUPT_H #define LIBTORRENT_UTILS_THREAD_INTERRUPT_H +#include #include #include @@ -44,7 +9,7 @@ namespace torrent { class SocketFd; -class LIBTORRENT_EXPORT lt_cacheline_aligned thread_interrupt : public Event { +class LIBTORRENT_EXPORT thread_interrupt : public Event { public: typedef std::pair pair_type; @@ -52,8 +17,6 @@ class LIBTORRENT_EXPORT lt_cacheline_aligned thread_interrupt : public Event { static pair_type create_pair(); - bool is_poking() const; - bool poke(); void event_read(); @@ -66,14 +29,9 @@ class LIBTORRENT_EXPORT lt_cacheline_aligned thread_interrupt : public Event { SocketFd& get_fd() { return *reinterpret_cast(&m_fileDesc); } thread_interrupt* m_other; - bool m_poking lt_cacheline_aligned; + std::atomic_flag m_poking; }; -inline bool -thread_interrupt::is_poking() const { - return m_poking; -} - } #endif From e7a02cad7dbf639438e8161cb2af38136f84ff20 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Mon, 2 Dec 2024 09:02:24 +0000 Subject: [PATCH 5/5] Fixed signal_bitfield name collision. --- src/torrent/utils/thread_base.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/torrent/utils/thread_base.h b/src/torrent/utils/thread_base.h index 8706546fb..17f194f93 100644 --- a/src/torrent/utils/thread_base.h +++ b/src/torrent/utils/thread_base.h @@ -19,6 +19,7 @@ class LIBTORRENT_EXPORT thread_base { typedef void* (*pthread_func)(void*); typedef std::function slot_void; typedef std::function slot_timer; + typedef class signal_bitfield signal_bitfield_t; enum state_type { STATE_UNKNOWN, @@ -54,7 +55,7 @@ class LIBTORRENT_EXPORT thread_base { virtual const char* name() const = 0; Poll* poll() { return m_poll; } - signal_bitfield* signal_bitfield() { return &m_signal_bitfield; } + signal_bitfield_t* signal_bitfield() { return &m_signal_bitfield; } pthread_t pthread() { return m_thread; } virtual void init_thread() = 0; @@ -95,10 +96,10 @@ class LIBTORRENT_EXPORT thread_base { std::atomic m_state; std::atomic m_flags; - int m_instrumentation_index; + int m_instrumentation_index; - Poll* m_poll; - class signal_bitfield m_signal_bitfield; + Poll* m_poll; + signal_bitfield_t m_signal_bitfield; slot_void m_slot_do_work; slot_timer m_slot_next_timeout;