]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Add explicit reference-counting base class
authordanieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7>
Wed, 30 Sep 2009 21:55:21 +0000 (21:55 +0000)
committerdanieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7>
Wed, 30 Sep 2009 21:55:21 +0000 (21:55 +0000)
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@11785 e03df62e-2008-0410-955e-edbf42e46eb7

12 files changed:
include/base.h
include/inspsocket.h
include/users.h
src/base.cpp
src/configreader.cpp
src/cull_list.cpp
src/inspsocket.cpp
src/modules/m_spanningtree/main.cpp
src/modules/m_spanningtree/main.h
src/modules/m_spanningtree/utils.cpp
src/modules/m_spanningtree/utils.h
src/users.cpp

index b66051cafe7a365d0b718d07c0ae048696328c74..f41ea07d2b4ee47bebdbbef3a65c10f4d62da3bc 100644 (file)
@@ -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 <typename T>
+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<T>& operator=(const reference<T>& 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.
index 73aa748a0326384f50627166614d2e9c61eb4407..84716eae67ee0691b7597f0a3eb1775472b58ca3 100644 (file)
@@ -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
index 76337b2c337edfec83f3c7a5e0ea27b5db7b69c6..31c1c641d8328b8855e95838664093ebc8162418 100644 (file)
@@ -62,7 +62,7 @@ class UserResolver;
 
 /** Holds information relevent to &lt;connect allow&gt; and &lt;connect deny&gt; 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<irc::string, time_t> > InvitedList;
 
 /** Holds a complete list of all allow and deny tags from the configuration file (connection classes)
  */
-typedef std::vector<ConnectClass*> ClassVector;
+typedef std::vector<reference<ConnectClass> > 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<ConnectClass> 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.
index 76e469482d56759798f86860b02653691d9a2d32..9307928540639b721cda966221dac65cdd06cb27 100644 (file)
@@ -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)
index 21bfce3db84f217e8e260af43fd88f7f71a5a459..86d0b3c5e5ee7e935ca91a279bbf7c9661e7a6e6 100644 (file)
@@ -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() ? "<all>" : 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() ? "<all>" : 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<ConnectClass*>::iterator i = removed_classes.begin(); i != removed_classes.end(); i++)
-       {
-               ConnectClass* c = *i;
-               if (0 == --c->RefCount)
-                       delete c;
-       }
 }
 
 void ServerConfig::ApplyModules(User* user)
index 5715c314766bef230682b141452caa5d719bbac4..02776aff84ed933a7b1ae6f371ce8dd3d6cc16aa 100644 (file)
@@ -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
                {
index 062f6b644bc27fb04d8bc775cf00697692419d00..ebf6e3b9d3c7d31f0eda122caf038b7534c739cb 100644 (file)
@@ -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)
index db40c7f6a033bf5934834cd76d80d4c7074e3108..501baa2904bd5b1dbdd68bfc1704daaa2d4ff40b 100644 (file)
@@ -939,9 +939,9 @@ void ModuleSpanningTree::OnEvent(Event* event)
        }
 }
 
-void ModuleSpanningTree::cull()
+bool ModuleSpanningTree::cull()
 {
-       Utils->cull();
+       return Utils->cull();
 }
 
 ModuleSpanningTree::~ModuleSpanningTree()
index 6e3f620565bfaafb173ec99578bcce6668b6860b..429c0d4bd398330c738c92233e4838ffadf132b3 100644 (file)
@@ -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();
index fc5356c66d56ce7bb7f349eb55b5b233143560a8..6f94ead60ed9021de4761aa5162adf5eafbf08b5 100644 (file)
@@ -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)
index 1de6de076157dcf5994671f8f6c67d29c3ed614f..d1922ed751791f609f245fc9b11b5380d5a95fab 100644 (file)
@@ -166,7 +166,7 @@ class SpanningTreeUtilities : public classbase
 
        /** Prepare for class destruction
         */
-       void cull();
+       bool cull();
 
        /** Destroy class and free listeners etc
         */
index f5eeff9424c545a24d6833e61c44bb5265fd947e..236df2d65ef76ebf9ca556559b2fac39178557d3 100644 (file)
@@ -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)
 {
 }