00001 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 00002 /* 00003 * Copyright (c) 2007 INESC Porto 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation; 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 * 00018 * Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt> 00019 */ 00020 #include "event-garbage-collector.h" 00021 00022 #define CLEANUP_CHUNK_MIN_SIZE 8 00023 #define CLEANUP_CHUNK_MAX_SIZE 128 00024 00025 00026 namespace ns3 { 00027 00028 00029 EventGarbageCollector::EventGarbageCollector () : 00030 m_nextCleanupSize (CLEANUP_CHUNK_MIN_SIZE) 00031 {} 00032 00033 void 00034 EventGarbageCollector::Track (EventId event) 00035 { 00036 m_events.insert (event); 00037 if (m_events.size () >= m_nextCleanupSize) 00038 Cleanup (); 00039 } 00040 00041 void 00042 EventGarbageCollector::Grow () 00043 { 00044 m_nextCleanupSize += (m_nextCleanupSize < CLEANUP_CHUNK_MAX_SIZE? 00045 m_nextCleanupSize : CLEANUP_CHUNK_MAX_SIZE); 00046 } 00047 00048 void 00049 EventGarbageCollector::Shrink () 00050 { 00051 while (m_nextCleanupSize > m_events.size ()) 00052 m_nextCleanupSize >>= 1; 00053 Grow (); 00054 } 00055 00056 // Called when a new event was added and the cleanup limit was exceeded in consequence. 00057 void 00058 EventGarbageCollector::Cleanup () 00059 { 00060 for (EventList::iterator iter = m_events.begin (); iter != m_events.end ();) 00061 { 00062 if ((*iter).IsExpired ()) 00063 { 00064 m_events.erase (iter++); 00065 } 00066 else 00067 break; // EventIds are sorted by timestamp => further events are not expired for sure 00068 } 00069 00070 // If after cleanup we are still over the limit, increase the limit. 00071 if (m_events.size () >= m_nextCleanupSize) 00072 Grow (); 00073 else 00074 Shrink (); 00075 } 00076 00077 00078 EventGarbageCollector::~EventGarbageCollector () 00079 { 00080 for (EventList::iterator event = m_events.begin (); 00081 event != m_events.end (); event++) 00082 { 00083 Simulator::Cancel (*event); 00084 } 00085 } 00086 00087 }; // namespace ns3 00088 00089 00090 00091 #ifdef RUN_SELF_TESTS 00092 00093 #include "ns3/test.h" 00094 00095 namespace ns3 { 00096 00097 class EventGarbageCollectorTests : public Test 00098 { 00099 int m_counter; 00100 EventGarbageCollector *m_events; 00101 00102 void EventGarbageCollectorCallback (); 00103 00104 public: 00105 00106 EventGarbageCollectorTests (); 00107 virtual ~EventGarbageCollectorTests (); 00108 virtual bool RunTests (void); 00109 }; 00110 00111 EventGarbageCollectorTests::EventGarbageCollectorTests () 00112 : Test ("EventGarbageCollector"), m_counter (0), m_events (0) 00113 {} 00114 00115 EventGarbageCollectorTests::~EventGarbageCollectorTests () 00116 {} 00117 00118 void 00119 EventGarbageCollectorTests::EventGarbageCollectorCallback () 00120 { 00121 m_counter++; 00122 if (m_counter == 50) 00123 { 00124 // this should cause the remaining (50) events to be cancelled 00125 delete m_events; 00126 m_events = 0; 00127 } 00128 } 00129 00130 bool EventGarbageCollectorTests::RunTests (void) 00131 { 00132 bool result = true; 00133 00134 m_events = new EventGarbageCollector (); 00135 00136 for (int n = 0; n < 100; n++) 00137 { 00138 m_events->Track (Simulator::Schedule 00139 (Simulator::Now (), 00140 &EventGarbageCollectorTests::EventGarbageCollectorCallback, 00141 this)); 00142 } 00143 Simulator::Run (); 00144 NS_TEST_ASSERT_EQUAL (m_events, 0); 00145 NS_TEST_ASSERT_EQUAL (m_counter, 50); 00146 return result; 00147 } 00148 00149 static EventGarbageCollectorTests g_eventCollectorTests; 00150 00151 }; 00152 00153 #endif /* RUN_SELF_TESTS */