/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2019-2023 Sadie Powell * Copyright (C) 2015 Attila Molnar * Copyright (C) 2012 Robby * Copyright (C) 2011 jackmcbarn * Copyright (C) 2009 Daniel De Graaf * Copyright (C) 2007 Dennis Friis * Copyright (C) 2007 Craig Edwards * * This file is part of InspIRCd. InspIRCd 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, version 2. * * 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, see . */ #include "inspircd.h" #ifdef INSPIRCD_ENABLE_RTTI # include #endif #include Cullable::Cullable() { #ifdef INSPIRCD_ENABLE_RTTI if (ServerInstance) { ServerInstance->Logs.Debug("CULL", "Cullable::+{} @{}", typeid(*this).name(), fmt::ptr(this)); } #endif } Cullable::~Cullable() { #ifdef INSPIRCD_ENABLE_RTTI if (ServerInstance) { ServerInstance->Logs.Debug("CULL", "Cullable::~{} @{}", typeid(*this).name(), fmt::ptr(this)); } #endif } Cullable::Result Cullable::Cull() { #ifdef INSPIRCD_ENABLE_RTTI if (ServerInstance) { ServerInstance->Logs.Debug("CULL", "Cullable::-{} @{}", typeid(*this).name(), fmt::ptr(this)); } #endif return {}; } void CullList::Apply() { std::vector working; while (!SQlist.empty()) { working.swap(SQlist); for (auto* u : working) { ServerInstance->SNO.WriteGlobalSno('a', "User {} SendQ exceeds connect class maximum of {}", u->nick, u->GetClass()->hardsendqmax); ServerInstance->Users.QuitUser(u, "SendQ exceeded"); } working.clear(); } std::unordered_set culled; std::vector deletable; culled.reserve(list.size() + 32); // IMPORTANT: we can't use a range-based for loop here as culling an object // may invalidate the list iterators. for (size_t idx = 0; idx < list.size(); ++idx) { auto* c = list[idx]; if (culled.insert(c).second) { #ifdef INSPIRCD_ENABLE_RTTI ServerInstance->Logs.Debug("CULL", "Culling {} @{}", typeid(*c).name(), fmt::ptr(c)); #endif c->Cull(); // IMPORTANT: we have to use two containers here because some objects // have to be deleted in the same order they were culled in. deletable.push_back(c); } else { #ifdef INSPIRCD_ENABLE_RTTI ServerInstance->Logs.Debug("CULL", "BUG: {} @{} was added to the cull list twice!", typeid(*c).name(), fmt::ptr(c)); #else ServerInstance->Logs.Debug("CULL", "BUG: @{} was added to the cull list twice!", fmt::ptr(c)); #endif } } list.clear(); for (auto* c : deletable) { #ifdef INSPIRCD_ENABLE_RTTI ServerInstance->Logs.Debug("CULL", "Deleting {} @{}", typeid(*c).name(), fmt::ptr(c)); #endif delete c; } if (!list.empty()) { ServerInstance->Logs.Debug("CULL", "BUG: {} objects were added to the cull list from a destructor", list.size()); Apply(); } } void ActionList::Run() { // IMPORTANT: we can't use a range-based for loop here as adding to the list // may invalidate the list iterators. for (size_t idx = 0; idx < list.size(); ++idx) list[idx]->Call(); list.clear(); }