1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/tests/TestExpirationTracker.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,204 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include <stdlib.h> 1.11 +#include <stdio.h> 1.12 +#include <prthread.h> 1.13 +#include "nsExpirationTracker.h" 1.14 +#include "nsMemory.h" 1.15 +#include "nsAutoPtr.h" 1.16 +#include "nsString.h" 1.17 +#include "nsDirectoryServiceDefs.h" 1.18 +#include "nsDirectoryServiceUtils.h" 1.19 +#include "nsComponentManagerUtils.h" 1.20 +#include "nsXPCOM.h" 1.21 +#include "nsIFile.h" 1.22 +#include "prinrval.h" 1.23 +#include "nsThreadUtils.h" 1.24 + 1.25 +namespace TestExpirationTracker { 1.26 + 1.27 +struct Object { 1.28 + Object() : mExpired(false) { Touch(); } 1.29 + void Touch() { mLastUsed = PR_IntervalNow(); mExpired = false; } 1.30 + 1.31 + nsExpirationState mExpiration; 1.32 + nsExpirationState* GetExpirationState() { return &mExpiration; } 1.33 + 1.34 + PRIntervalTime mLastUsed; 1.35 + bool mExpired; 1.36 +}; 1.37 + 1.38 +static bool error; 1.39 +static uint32_t periodMS = 100; 1.40 +static uint32_t ops = 1000; 1.41 +static uint32_t iterations = 2; 1.42 +static bool logging = 0; 1.43 +static uint32_t sleepPeriodMS = 50; 1.44 +static uint32_t slackMS = 20; // allow this much error 1.45 + 1.46 +static void SignalError() { 1.47 + printf("ERROR!\n"); 1.48 + error = true; 1.49 +} 1.50 + 1.51 +template <uint32_t K> class Tracker : public nsExpirationTracker<Object,K> { 1.52 +public: 1.53 + Tracker() : nsExpirationTracker<Object,K>(periodMS) { 1.54 + Object* obj = new Object(); 1.55 + mUniverse.AppendElement(obj); 1.56 + LogAction(obj, "Created"); 1.57 + } 1.58 + 1.59 + nsTArray<nsAutoArrayPtr<Object> > mUniverse; 1.60 + 1.61 + void LogAction(Object* aObj, const char* aAction) { 1.62 + if (logging) { 1.63 + printf("%d %p(%d): %s\n", PR_IntervalNow(), 1.64 + static_cast<void*>(aObj), aObj->mLastUsed, aAction); 1.65 + } 1.66 + } 1.67 + 1.68 + void DoRandomOperation() { 1.69 + Object* obj; 1.70 + switch (rand() & 0x7) { 1.71 + case 0: { 1.72 + if (mUniverse.Length() < 50) { 1.73 + obj = new Object(); 1.74 + mUniverse.AppendElement(obj); 1.75 + nsExpirationTracker<Object,K>::AddObject(obj); 1.76 + LogAction(obj, "Created and added"); 1.77 + } 1.78 + break; 1.79 + } 1.80 + case 4: { 1.81 + if (mUniverse.Length() < 50) { 1.82 + obj = new Object(); 1.83 + mUniverse.AppendElement(obj); 1.84 + LogAction(obj, "Created"); 1.85 + } 1.86 + break; 1.87 + } 1.88 + case 1: { 1.89 + obj = mUniverse[uint32_t(rand())%mUniverse.Length()]; 1.90 + if (obj->mExpiration.IsTracked()) { 1.91 + nsExpirationTracker<Object,K>::RemoveObject(obj); 1.92 + LogAction(obj, "Removed"); 1.93 + } 1.94 + break; 1.95 + } 1.96 + case 2: { 1.97 + obj = mUniverse[uint32_t(rand())%mUniverse.Length()]; 1.98 + if (!obj->mExpiration.IsTracked()) { 1.99 + obj->Touch(); 1.100 + nsExpirationTracker<Object,K>::AddObject(obj); 1.101 + LogAction(obj, "Added"); 1.102 + } 1.103 + break; 1.104 + } 1.105 + case 3: { 1.106 + obj = mUniverse[uint32_t(rand())%mUniverse.Length()]; 1.107 + if (obj->mExpiration.IsTracked()) { 1.108 + obj->Touch(); 1.109 + nsExpirationTracker<Object,K>::MarkUsed(obj); 1.110 + LogAction(obj, "Marked used"); 1.111 + } 1.112 + break; 1.113 + } 1.114 + } 1.115 + } 1.116 + 1.117 +protected: 1.118 + void NotifyExpired(Object* aObj) { 1.119 + LogAction(aObj, "Expired"); 1.120 + PRIntervalTime now = PR_IntervalNow(); 1.121 + uint32_t timeDiffMS = (now - aObj->mLastUsed)*1000/PR_TicksPerSecond(); 1.122 + // See the comment for NotifyExpired in nsExpirationTracker.h for these 1.123 + // bounds 1.124 + uint32_t lowerBoundMS = (K-1)*periodMS - slackMS; 1.125 + uint32_t upperBoundMS = K*(periodMS + sleepPeriodMS) + slackMS; 1.126 + if (logging) { 1.127 + printf("Checking: %d-%d = %d [%d,%d]\n", 1.128 + now, aObj->mLastUsed, timeDiffMS, lowerBoundMS, upperBoundMS); 1.129 + } 1.130 + if (timeDiffMS < lowerBoundMS || timeDiffMS > upperBoundMS) { 1.131 + if (timeDiffMS < periodMS && aObj->mExpired) { 1.132 + // This is probably OK, it probably just expired twice 1.133 + } else { 1.134 + SignalError(); 1.135 + } 1.136 + } 1.137 + aObj->Touch(); 1.138 + aObj->mExpired = true; 1.139 + DoRandomOperation(); 1.140 + DoRandomOperation(); 1.141 + DoRandomOperation(); 1.142 + } 1.143 +}; 1.144 + 1.145 +template <uint32_t K> static bool test_random() { 1.146 + srand(K); 1.147 + error = false; 1.148 + 1.149 + for (uint32_t j = 0; j < iterations; ++j) { 1.150 + Tracker<K> tracker; 1.151 + 1.152 + uint32_t i = 0; 1.153 + for (i = 0; i < ops; ++i) { 1.154 + if ((rand() & 0xF) == 0) { 1.155 + // Simulate work that takes time 1.156 + if (logging) { 1.157 + printf("SLEEPING for %dms (%d)\n", sleepPeriodMS, PR_IntervalNow()); 1.158 + } 1.159 + PR_Sleep(PR_MillisecondsToInterval(sleepPeriodMS)); 1.160 + // Process pending timer events 1.161 + NS_ProcessPendingEvents(nullptr); 1.162 + } 1.163 + tracker.DoRandomOperation(); 1.164 + } 1.165 + } 1.166 + 1.167 + return !error; 1.168 +} 1.169 + 1.170 +static bool test_random3() { return test_random<3>(); } 1.171 +static bool test_random4() { return test_random<4>(); } 1.172 +static bool test_random8() { return test_random<8>(); } 1.173 + 1.174 +typedef bool (*TestFunc)(); 1.175 +#define DECL_TEST(name) { #name, name } 1.176 + 1.177 +static const struct Test { 1.178 + const char* name; 1.179 + TestFunc func; 1.180 +} tests[] = { 1.181 + DECL_TEST(test_random3), 1.182 + DECL_TEST(test_random4), 1.183 + DECL_TEST(test_random8), 1.184 + { nullptr, nullptr } 1.185 +}; 1.186 + 1.187 +} 1.188 + 1.189 +using namespace TestExpirationTracker; 1.190 + 1.191 +int main(int argc, char **argv) { 1.192 + int count = 1; 1.193 + if (argc > 1) 1.194 + count = atoi(argv[1]); 1.195 + 1.196 + if (NS_FAILED(NS_InitXPCOM2(nullptr, nullptr, nullptr))) 1.197 + return -1; 1.198 + 1.199 + while (count--) { 1.200 + for (const Test* t = tests; t->name != nullptr; ++t) { 1.201 + printf("%25s : %s\n", t->name, t->func() ? "SUCCESS" : "FAILURE"); 1.202 + } 1.203 + } 1.204 + 1.205 + NS_ShutdownXPCOM(nullptr); 1.206 + return 0; 1.207 +}