1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/tests/TestRacingServiceManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,305 @@ 1.4 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "TestHarness.h" 1.10 + 1.11 +#include "nsIFactory.h" 1.12 +#include "mozilla/Module.h" 1.13 +#include "nsXULAppAPI.h" 1.14 +#include "nsIThread.h" 1.15 +#include "nsIComponentRegistrar.h" 1.16 + 1.17 +#include "nsAutoPtr.h" 1.18 +#include "nsThreadUtils.h" 1.19 +#include "nsXPCOMCIDInternal.h" 1.20 +#include "pratom.h" 1.21 +#include "prmon.h" 1.22 +#include "mozilla/Attributes.h" 1.23 + 1.24 +#include "mozilla/ReentrantMonitor.h" 1.25 +using namespace mozilla; 1.26 + 1.27 +#ifdef DEBUG 1.28 +#define TEST_ASSERTION(_test, _msg) \ 1.29 + NS_ASSERTION(_test, _msg); 1.30 +#else 1.31 +#define TEST_ASSERTION(_test, _msg) \ 1.32 + PR_BEGIN_MACRO \ 1.33 + if (!(_test)) { \ 1.34 + NS_DebugBreak(NS_DEBUG_ABORT, _msg, #_test, __FILE__, __LINE__); \ 1.35 + } \ 1.36 + PR_END_MACRO 1.37 +#endif 1.38 + 1.39 +/* f93f6bdc-88af-42d7-9d64-1b43c649a3e5 */ 1.40 +#define FACTORY_CID1 \ 1.41 +{ \ 1.42 + 0xf93f6bdc, \ 1.43 + 0x88af, \ 1.44 + 0x42d7, \ 1.45 + { 0x9d, 0x64, 0x1b, 0x43, 0xc6, 0x49, 0xa3, 0xe5 } \ 1.46 +} 1.47 +NS_DEFINE_CID(kFactoryCID1, FACTORY_CID1); 1.48 + 1.49 +/* ef38ad65-6595-49f0-8048-e819f81d15e2 */ 1.50 +#define FACTORY_CID2 \ 1.51 +{ \ 1.52 + 0xef38ad65, \ 1.53 + 0x6595, \ 1.54 + 0x49f0, \ 1.55 + { 0x80, 0x48, 0xe8, 0x19, 0xf8, 0x1d, 0x15, 0xe2 } \ 1.56 +} 1.57 +NS_DEFINE_CID(kFactoryCID2, FACTORY_CID2); 1.58 + 1.59 +#define FACTORY_CONTRACTID \ 1.60 + "TestRacingThreadManager/factory;1" 1.61 + 1.62 +int32_t gComponent1Count = 0; 1.63 +int32_t gComponent2Count = 0; 1.64 + 1.65 +ReentrantMonitor* gReentrantMonitor = nullptr; 1.66 + 1.67 +bool gCreateInstanceCalled = false; 1.68 +bool gMainThreadWaiting = false; 1.69 + 1.70 +class AutoCreateAndDestroyReentrantMonitor 1.71 +{ 1.72 +public: 1.73 + AutoCreateAndDestroyReentrantMonitor(ReentrantMonitor** aReentrantMonitorPtr) 1.74 + : mReentrantMonitorPtr(aReentrantMonitorPtr) { 1.75 + *aReentrantMonitorPtr = 1.76 + new ReentrantMonitor("TestRacingServiceManager::AutoMon"); 1.77 + TEST_ASSERTION(*aReentrantMonitorPtr, "Out of memory!"); 1.78 + } 1.79 + 1.80 + ~AutoCreateAndDestroyReentrantMonitor() { 1.81 + if (*mReentrantMonitorPtr) { 1.82 + delete *mReentrantMonitorPtr; 1.83 + *mReentrantMonitorPtr = nullptr; 1.84 + } 1.85 + } 1.86 + 1.87 +private: 1.88 + ReentrantMonitor** mReentrantMonitorPtr; 1.89 +}; 1.90 + 1.91 +class Factory MOZ_FINAL : public nsIFactory 1.92 +{ 1.93 +public: 1.94 + NS_DECL_THREADSAFE_ISUPPORTS 1.95 + 1.96 + Factory() : mFirstComponentCreated(false) { } 1.97 + 1.98 + NS_IMETHOD CreateInstance(nsISupports* aDelegate, 1.99 + const nsIID& aIID, 1.100 + void** aResult); 1.101 + 1.102 + NS_IMETHOD LockFactory(bool aLock) { 1.103 + return NS_OK; 1.104 + } 1.105 + 1.106 + bool mFirstComponentCreated; 1.107 +}; 1.108 + 1.109 +NS_IMPL_ISUPPORTS(Factory, nsIFactory) 1.110 + 1.111 +class Component1 MOZ_FINAL : public nsISupports 1.112 +{ 1.113 +public: 1.114 + NS_DECL_THREADSAFE_ISUPPORTS 1.115 + 1.116 + Component1() { 1.117 + // This is the real test - make sure that only one instance is ever created. 1.118 + int32_t count = PR_AtomicIncrement(&gComponent1Count); 1.119 + TEST_ASSERTION(count == 1, "Too many components created!"); 1.120 + } 1.121 +}; 1.122 + 1.123 +NS_IMPL_ADDREF(Component1) 1.124 +NS_IMPL_RELEASE(Component1) 1.125 + 1.126 +NS_INTERFACE_MAP_BEGIN(Component1) 1.127 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.128 +NS_INTERFACE_MAP_END 1.129 + 1.130 +class Component2 MOZ_FINAL : public nsISupports 1.131 +{ 1.132 +public: 1.133 + NS_DECL_THREADSAFE_ISUPPORTS 1.134 + 1.135 + Component2() { 1.136 + // This is the real test - make sure that only one instance is ever created. 1.137 + int32_t count = PR_AtomicIncrement(&gComponent2Count); 1.138 + TEST_ASSERTION(count == 1, "Too many components created!"); 1.139 + } 1.140 +}; 1.141 + 1.142 +NS_IMPL_ADDREF(Component2) 1.143 +NS_IMPL_RELEASE(Component2) 1.144 + 1.145 +NS_INTERFACE_MAP_BEGIN(Component2) 1.146 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.147 +NS_INTERFACE_MAP_END 1.148 + 1.149 +NS_IMETHODIMP 1.150 +Factory::CreateInstance(nsISupports* aDelegate, 1.151 + const nsIID& aIID, 1.152 + void** aResult) 1.153 +{ 1.154 + // Make sure that the second thread beat the main thread to the getService 1.155 + // call. 1.156 + TEST_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.157 + 1.158 + { 1.159 + ReentrantMonitorAutoEnter mon(*gReentrantMonitor); 1.160 + 1.161 + gCreateInstanceCalled = true; 1.162 + mon.Notify(); 1.163 + 1.164 + mon.Wait(PR_MillisecondsToInterval(3000)); 1.165 + } 1.166 + 1.167 + NS_ENSURE_FALSE(aDelegate, NS_ERROR_NO_AGGREGATION); 1.168 + NS_ENSURE_ARG_POINTER(aResult); 1.169 + 1.170 + nsCOMPtr<nsISupports> instance; 1.171 + 1.172 + if (!mFirstComponentCreated) { 1.173 + instance = new Component1(); 1.174 + } 1.175 + else { 1.176 + instance = new Component2(); 1.177 + } 1.178 + NS_ENSURE_TRUE(instance, NS_ERROR_OUT_OF_MEMORY); 1.179 + 1.180 + nsresult rv = instance->QueryInterface(aIID, aResult); 1.181 + NS_ENSURE_SUCCESS(rv, rv); 1.182 + 1.183 + return NS_OK; 1.184 +} 1.185 + 1.186 +class Runnable : public nsRunnable 1.187 +{ 1.188 +public: 1.189 + NS_DECL_NSIRUNNABLE 1.190 + 1.191 + Runnable() : mFirstRunnableDone(false) { } 1.192 + 1.193 + bool mFirstRunnableDone; 1.194 +}; 1.195 + 1.196 +NS_IMETHODIMP 1.197 +Runnable::Run() 1.198 +{ 1.199 + { 1.200 + ReentrantMonitorAutoEnter mon(*gReentrantMonitor); 1.201 + 1.202 + while (!gMainThreadWaiting) { 1.203 + mon.Wait(); 1.204 + } 1.205 + } 1.206 + 1.207 + nsresult rv; 1.208 + nsCOMPtr<nsISupports> component; 1.209 + 1.210 + if (!mFirstRunnableDone) { 1.211 + component = do_GetService(kFactoryCID1, &rv); 1.212 + } 1.213 + else { 1.214 + component = do_GetService(FACTORY_CONTRACTID, &rv); 1.215 + } 1.216 + TEST_ASSERTION(NS_SUCCEEDED(rv), "GetService failed!"); 1.217 + 1.218 + return NS_OK; 1.219 +} 1.220 + 1.221 +static Factory* gFactory; 1.222 + 1.223 +static already_AddRefed<nsIFactory> 1.224 +CreateFactory(const mozilla::Module& module, const mozilla::Module::CIDEntry& entry) 1.225 +{ 1.226 + if (!gFactory) { 1.227 + gFactory = new Factory(); 1.228 + NS_ADDREF(gFactory); 1.229 + } 1.230 + nsCOMPtr<nsIFactory> ret = gFactory; 1.231 + return ret.forget(); 1.232 +} 1.233 + 1.234 +static const mozilla::Module::CIDEntry kLocalCIDs[] = { 1.235 + { &kFactoryCID1, false, CreateFactory, nullptr }, 1.236 + { &kFactoryCID2, false, CreateFactory, nullptr }, 1.237 + { nullptr } 1.238 +}; 1.239 + 1.240 +static const mozilla::Module::ContractIDEntry kLocalContracts[] = { 1.241 + { FACTORY_CONTRACTID, &kFactoryCID2 }, 1.242 + { nullptr } 1.243 +}; 1.244 + 1.245 +static const mozilla::Module kLocalModule = { 1.246 + mozilla::Module::kVersion, 1.247 + kLocalCIDs, 1.248 + kLocalContracts 1.249 +}; 1.250 + 1.251 +int main(int argc, char** argv) 1.252 +{ 1.253 + nsresult rv; 1.254 + XRE_AddStaticComponent(&kLocalModule); 1.255 + 1.256 + ScopedXPCOM xpcom("RacingServiceManager"); 1.257 + NS_ENSURE_FALSE(xpcom.failed(), 1); 1.258 + 1.259 + AutoCreateAndDestroyReentrantMonitor mon(&gReentrantMonitor); 1.260 + 1.261 + nsRefPtr<Runnable> runnable = new Runnable(); 1.262 + NS_ENSURE_TRUE(runnable, 1); 1.263 + 1.264 + // Run the classID test 1.265 + nsCOMPtr<nsIThread> newThread; 1.266 + rv = NS_NewThread(getter_AddRefs(newThread), runnable); 1.267 + NS_ENSURE_SUCCESS(rv, 1); 1.268 + 1.269 + { 1.270 + ReentrantMonitorAutoEnter mon(*gReentrantMonitor); 1.271 + 1.272 + gMainThreadWaiting = true; 1.273 + mon.Notify(); 1.274 + 1.275 + while (!gCreateInstanceCalled) { 1.276 + mon.Wait(); 1.277 + } 1.278 + } 1.279 + 1.280 + nsCOMPtr<nsISupports> component(do_GetService(kFactoryCID1, &rv)); 1.281 + NS_ENSURE_SUCCESS(rv, 1); 1.282 + 1.283 + // Reset for the contractID test 1.284 + gMainThreadWaiting = gCreateInstanceCalled = false; 1.285 + gFactory->mFirstComponentCreated = runnable->mFirstRunnableDone = true; 1.286 + component = nullptr; 1.287 + 1.288 + rv = newThread->Dispatch(runnable, NS_DISPATCH_NORMAL); 1.289 + NS_ENSURE_SUCCESS(rv, 1); 1.290 + 1.291 + { 1.292 + ReentrantMonitorAutoEnter mon(*gReentrantMonitor); 1.293 + 1.294 + gMainThreadWaiting = true; 1.295 + mon.Notify(); 1.296 + 1.297 + while (!gCreateInstanceCalled) { 1.298 + mon.Wait(); 1.299 + } 1.300 + } 1.301 + 1.302 + component = do_GetService(FACTORY_CONTRACTID, &rv); 1.303 + NS_ENSURE_SUCCESS(rv, 1); 1.304 + 1.305 + NS_RELEASE(gFactory); 1.306 + 1.307 + return 0; 1.308 +}