From 3dc81ee1331d1b37ee85be9bf0d843e3b6827a2d Mon Sep 17 00:00:00 2001 From: danieldg Date: Wed, 30 Sep 2009 21:55:21 +0000 Subject: Add explicit reference-counting base class git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@11785 e03df62e-2008-0410-955e-edbf42e46eb7 --- include/base.h | 110 +++++++++++++++++------------------ include/inspsocket.h | 2 +- include/users.h | 15 ++--- src/base.cpp | 51 ++-------------- src/configreader.cpp | 39 +++++-------- src/cull_list.cpp | 4 +- src/inspsocket.cpp | 3 +- src/modules/m_spanningtree/main.cpp | 4 +- src/modules/m_spanningtree/main.h | 2 +- src/modules/m_spanningtree/utils.cpp | 7 ++- src/modules/m_spanningtree/utils.h | 2 +- src/users.cpp | 35 +++-------- 12 files changed, 99 insertions(+), 175 deletions(-) diff --git a/include/base.h b/include/base.h index b66051caf..f41ea07d2 100644 --- a/include/base.h +++ b/include/base.h @@ -28,71 +28,69 @@ class CoreExport classbase public: classbase(); - // Called just prior to destruction via cull list - virtual void cull(); + /** + * Called just prior to destruction via cull list. + * + * @return true to allow the delete, or false to halt the delete + */ + virtual bool cull(); virtual ~classbase(); }; -/** BoolSet is a utility class designed to hold eight bools in a bitmask. - * Use BoolSet::Set and BoolSet::Get to set and get bools in the bitmask, - * and Unset and Invert for special operations upon them. +/** The base class for inspircd classes that support reference counting. + * Any objects that do not have a well-defined lifetime should inherit from + * this */ -class CoreExport BoolSet : public classbase +class CoreExport refcountbase : public classbase { - /** Actual bit values */ - char bits; - + unsigned int refcount; public: + refcountbase(); + virtual bool cull(); + virtual ~refcountbase(); + inline unsigned int GetReferenceCount() const { return refcount; } + friend class reference_base; +}; - /** The default constructor initializes the BoolSet to all values unset. - */ - BoolSet(); - - /** This constructor copies the default bitmask from a char - */ - BoolSet(char bitmask); - - /** The Set method sets one bool in the set. - * - * @param number The number of the item to set. This must be between 0 and 7. - */ - void Set(int number); - - /** The Get method returns the value of one bool in the set - * - * @param number The number of the item to retrieve. This must be between 0 and 7. - * - * @return True if the item is set, false if it is unset. - */ - bool Get(int number); - - /** The Unset method unsets one value in the set - * - * @param number The number of the item to set. This must be between 0 and 7. - */ - void Unset(int number); - - /** The Unset method inverts (flips) one value in the set - * - * @param number The number of the item to invert. This must be between 0 and 7. - */ - void Invert(int number); - - /** Compare two BoolSets - */ - bool operator==(BoolSet other); - - /** OR two BoolSets together - */ - BoolSet operator|(BoolSet other); +class CoreExport reference_base +{ + protected: + static inline unsigned int inc(refcountbase* v) { return ++(v->refcount); } + static inline unsigned int dec(refcountbase* v) { return --(v->refcount); } +}; - /** AND two BoolSets together - */ - BoolSet operator&(BoolSet other); +template +class CoreExport reference : public reference_base +{ + T* value; + public: + reference() : value(0) { } + reference(T* v) : value(v) { if (value) inc(value); } + reference(const reference& v) : value(v.value) { if (value) inc(value); } + reference& operator=(const reference& other) + { + if (other.value) + inc(other.value); + this->reference::~reference(); + value = other.value; + return *this; + } - /** Assign one BoolSet to another - */ - bool operator=(BoolSet other); + ~reference() + { + if (value) + { + int rc = dec(value); + if (rc == 0 && value->cull()) + delete value; + } + } + inline const T* operator->() const { return value; } + inline const T& operator*() const { return *value; } + inline T* operator->() { return value; } + inline T& operator*() { return *value; } + operator bool() const { return value; } + operator T*() const { return value; } }; /** This class can be used on its own to represent an exception, or derived to represent a module-specific exception. diff --git a/include/inspsocket.h b/include/inspsocket.h index 73aa748a0..84716eae6 100644 --- a/include/inspsocket.h +++ b/include/inspsocket.h @@ -146,7 +146,7 @@ class CoreExport StreamSocket : public EventHandler */ virtual void Close(); /** This ensures that close is called prior to destructor */ - virtual void cull(); + virtual bool cull(); }; /** * BufferedSocket is an extendable socket class which modules diff --git a/include/users.h b/include/users.h index 76337b2c3..31c1c641d 100644 --- a/include/users.h +++ b/include/users.h @@ -62,7 +62,7 @@ class UserResolver; /** Holds information relevent to <connect allow> and <connect deny> tags in the config file. */ -struct CoreExport ConnectClass : public classbase +struct CoreExport ConnectClass : public refcountbase { /** Type of line, either CC_ALLOW or CC_DENY */ @@ -127,12 +127,6 @@ struct CoreExport ConnectClass : public classbase */ unsigned long limit; - /** Reference counter. - * This will be 1 if no users are connected, as long as it is a valid connect block - * When it reaches 0, the object should be deleted - */ - unsigned long RefCount; - /** Create a new connect class with no settings. */ ConnectClass(char type, const std::string& mask); @@ -206,7 +200,7 @@ typedef std::vector< std::pair > InvitedList; /** Holds a complete list of all allow and deny tags from the configuration file (connection classes) */ -typedef std::vector ClassVector; +typedef std::vector > ClassVector; /** Typedef for the list of user-channel records for a user */ @@ -274,9 +268,8 @@ class CoreExport User : public StreamSocket static LocalStringExt OperQuit; /** Contains a pointer to the connect class a user is on from - this will be NULL for remote connections. - * The pointer is guarenteed to *always* be valid. :) */ - ConnectClass *MyClass; + reference MyClass; /** Hostname of connection. * This should be valid as per RFC1035. @@ -869,7 +862,7 @@ class CoreExport User : public StreamSocket /** Default destructor */ virtual ~User(); - virtual void cull(); + virtual bool cull(); }; /** Derived from Resolver, and performs user forward/reverse lookups. diff --git a/src/base.cpp b/src/base.cpp index 76e469482..930792854 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -26,65 +26,26 @@ classbase::classbase() { } -void classbase::cull() +bool classbase::cull() { + return true; } classbase::~classbase() { } -void BoolSet::Set(int number) -{ - this->bits |= bitfields[number]; -} - -void BoolSet::Unset(int number) -{ - this->bits &= inverted_bitfields[number]; -} - -void BoolSet::Invert(int number) -{ - this->bits ^= bitfields[number]; -} - -bool BoolSet::Get(int number) +refcountbase::refcountbase() : refcount(0) { - return ((this->bits | bitfields[number]) > 0); } -bool BoolSet::operator==(BoolSet other) +bool refcountbase::cull() { - return (this->bits == other.bits); + return (refcount == 0); } -BoolSet BoolSet::operator|(BoolSet other) +refcountbase::~refcountbase() { - BoolSet x(this->bits | other.bits); - return x; -} - -BoolSet BoolSet::operator&(BoolSet other) -{ - BoolSet x(this->bits & other.bits); - return x; -} - -BoolSet::BoolSet() -{ - this->bits = 0; -} - -BoolSet::BoolSet(char bitmask) -{ - this->bits = bitmask; -} - -bool BoolSet::operator=(BoolSet other) -{ - this->bits = other.bits; - return true; } ExtensionItem::ExtensionItem(const std::string& Key, Module* mod) : key(Key), owner(mod) diff --git a/src/configreader.cpp b/src/configreader.cpp index 21bfce3db..86d0b3c5e 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -727,11 +727,6 @@ void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current) Classes[i] = me; } } - - for(ClassMap::iterator toRemove = oldBlocksByMask.begin(); toRemove != oldBlocksByMask.end(); toRemove++) - { - removed_classes.push_back(toRemove->second); - } } @@ -1143,9 +1138,6 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) // write once here, to try it out and make sure its ok ServerInstance->WritePID(this->PID); - FailedPortList pl; - ServerInstance->BindPorts(pl); - /* * These values can only be set on boot. Keep their old values. Do it before we send messages so we actually have a servername. */ @@ -1153,18 +1145,23 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) { memcpy(this->ServerName, old->ServerName, sizeof(this->ServerName)); memcpy(this->sid, old->sid, sizeof(this->sid)); - } - - if (pl.size()) - { - errstr << "Not all your client ports could be bound.\nThe following port(s) failed to bind:\n"; + this->argv = old->argv; + this->argc = old->argc; - int j = 1; - for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++) + // Same for ports... they're bound later on first run. + FailedPortList pl; + ServerInstance->BindPorts(pl); + if (pl.size()) { - char buf[MAXBUF]; - snprintf(buf, MAXBUF, "%d. Address: %s Reason: %s\n", j, i->first.empty() ? "" : i->first.c_str(), i->second.c_str()); - errstr << buf; + errstr << "Not all your client ports could be bound.\nThe following port(s) failed to bind:\n"; + + int j = 1; + for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++) + { + char buf[MAXBUF]; + snprintf(buf, MAXBUF, "%d. Address: %s Reason: %s\n", j, i->first.empty() ? "" : i->first.c_str(), i->second.c_str()); + errstr << buf; + } } } @@ -1212,12 +1209,6 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) return; ApplyModules(user); - for (std::vector::iterator i = removed_classes.begin(); i != removed_classes.end(); i++) - { - ConnectClass* c = *i; - if (0 == --c->RefCount) - delete c; - } } void ServerConfig::ApplyModules(User* user) diff --git a/src/cull_list.cpp b/src/cull_list.cpp index 5715c3147..02776aff8 100644 --- a/src/cull_list.cpp +++ b/src/cull_list.cpp @@ -24,8 +24,8 @@ void CullList::Apply() { ServerInstance->Logs->Log("CULLLIST", DEBUG, "Deleting %s @%p", typeid(*c).name(), (void*)c); - c->cull(); - delete c; + if (c->cull()) + delete c; } else { diff --git a/src/inspsocket.cpp b/src/inspsocket.cpp index 062f6b644..ebf6e3b9d 100644 --- a/src/inspsocket.cpp +++ b/src/inspsocket.cpp @@ -139,9 +139,10 @@ void StreamSocket::Close() errno = save; } -void StreamSocket::cull() +bool StreamSocket::cull() { Close(); + return true; } bool StreamSocket::GetNextLine(std::string& line, char delim) diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index db40c7f6a..501baa290 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -939,9 +939,9 @@ void ModuleSpanningTree::OnEvent(Event* event) } } -void ModuleSpanningTree::cull() +bool ModuleSpanningTree::cull() { - Utils->cull(); + return Utils->cull(); } ModuleSpanningTree::~ModuleSpanningTree() diff --git a/src/modules/m_spanningtree/main.h b/src/modules/m_spanningtree/main.h index 6e3f62056..429c0d4bd 100644 --- a/src/modules/m_spanningtree/main.h +++ b/src/modules/m_spanningtree/main.h @@ -191,7 +191,7 @@ class ModuleSpanningTree : public Module void OnEvent(Event* event); void OnLoadModule(Module* mod,const std::string &name); void OnUnloadModule(Module* mod,const std::string &name); - void cull(); + bool cull(); ~ModuleSpanningTree(); Version GetVersion(); void Prioritize(); diff --git a/src/modules/m_spanningtree/utils.cpp b/src/modules/m_spanningtree/utils.cpp index fc5356c66..6f94ead60 100644 --- a/src/modules/m_spanningtree/utils.cpp +++ b/src/modules/m_spanningtree/utils.cpp @@ -157,7 +157,7 @@ SpanningTreeUtilities::SpanningTreeUtilities(ModuleSpanningTree* C) : Creator(C) this->ReadConfiguration(true); } -void SpanningTreeUtilities::cull() +bool SpanningTreeUtilities::cull() { for (unsigned int i = 0; i < Bindings.size(); i++) { @@ -175,7 +175,9 @@ void SpanningTreeUtilities::cull() } ServerUser->uuid = TreeRoot->GetID(); - ServerUser->cull(); + if (ServerUser->cull()) + delete ServerUser; + return true; } SpanningTreeUtilities::~SpanningTreeUtilities() @@ -186,7 +188,6 @@ SpanningTreeUtilities::~SpanningTreeUtilities() } delete TreeRoot; - delete ServerUser; } void SpanningTreeUtilities::AddThisServer(TreeServer* server, TreeServerList &list) diff --git a/src/modules/m_spanningtree/utils.h b/src/modules/m_spanningtree/utils.h index 1de6de076..d1922ed75 100644 --- a/src/modules/m_spanningtree/utils.h +++ b/src/modules/m_spanningtree/utils.h @@ -166,7 +166,7 @@ class SpanningTreeUtilities : public classbase /** Prepare for class destruction */ - void cull(); + bool cull(); /** Destroy class and free listeners etc */ diff --git a/src/users.cpp b/src/users.cpp index f5eeff942..236df2d65 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -568,14 +568,14 @@ void User::OnError(BufferedSocketError) ServerInstance->Users->QuitUser(this, getError()); } -void User::cull() +bool User::cull() { if (!quitting) ServerInstance->Users->QuitUser(this, "Culled without QuitUser"); if (uuid.empty()) { ServerInstance->Logs->Log("USERS", DEBUG, "User culled twice? UUID empty"); - return; + return true; } PurgeEmptyChannels(); if (IS_LOCAL(this)) @@ -590,14 +590,6 @@ void User::cull() ServerInstance->Logs->Log("USERS", DEBUG, "Failed to remove user from vector"); } - if (this->MyClass) - { - this->MyClass->RefCount--; - ServerInstance->Logs->Log("USERS", DEBUG, "User destructor -- connect refcount now: %lu", this->MyClass->RefCount); - if (MyClass->RefCount == 0) - delete MyClass; - } - if (this->AllowedOperCommands) { delete AllowedOperCommands; @@ -618,6 +610,7 @@ void User::cull() ServerInstance->Users->uuidlist->erase(uuid); uuid.clear(); + return true; } void User::Oper(const std::string &opertype, const std::string &opername) @@ -1658,7 +1651,7 @@ ConnectClass* User::SetClass(const std::string &explicit_name) * deny change if change will take class over the limit check it HERE, not after we found a matching class, * because we should attempt to find another class if this one doesn't match us. -- w00t */ - if (c->limit && (c->RefCount >= c->limit)) + if (c->limit && (c->GetReferenceCount() >= c->limit)) { ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "OOPS: Connect class limit (%lu) hit, denying", c->limit); continue; @@ -1688,20 +1681,7 @@ ConnectClass* User::SetClass(const std::string &explicit_name) */ if (found) { - /* only fiddle with refcounts if they are already in a class .. */ - if (this->MyClass) - { - if (found == this->MyClass) // no point changing this shit :P - return this->MyClass; - this->MyClass->RefCount--; - ServerInstance->Logs->Log("USERS", DEBUG, "Untying user from connect class -- refcount: %lu", this->MyClass->RefCount); - if (MyClass->RefCount == 0) - delete MyClass; - } - - this->MyClass = found; - this->MyClass->RefCount++; - ServerInstance->Logs->Log("USERS", DEBUG, "User tied to new class -- connect refcount now: %lu", this->MyClass->RefCount); + MyClass = found; } return this->MyClass; @@ -1824,8 +1804,7 @@ const std::string FakeUser::GetFullRealHost() ConnectClass::ConnectClass(char t, const std::string& mask) : type(t), name("unnamed"), registration_timeout(0), host(mask), pingtime(0), pass(""), hash(""), softsendqmax(0), hardsendqmax(0), - recvqmax(0), maxlocal(0), maxglobal(0), maxchans(0), port(0), limit(0), - RefCount(1) + recvqmax(0), maxlocal(0), maxglobal(0), maxchans(0), port(0), limit(0) { } @@ -1836,7 +1815,7 @@ ConnectClass::ConnectClass(char t, const std::string& mask, const ConnectClass& softsendqmax(parent.softsendqmax), hardsendqmax(parent.hardsendqmax), recvqmax(parent.recvqmax), maxlocal(parent.maxlocal), maxglobal(parent.maxglobal), maxchans(parent.maxchans), - port(parent.port), limit(parent.limit), RefCount(1) + port(parent.port), limit(parent.limit) { } -- cgit v1.2.3