1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/tests/TestThreads.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,223 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; 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 "nsThreadUtils.h" 1.10 +#include <stdio.h> 1.11 +#include <stdlib.h> 1.12 +#include "nspr.h" 1.13 +#include "nsCOMPtr.h" 1.14 +#include "nsIServiceManager.h" 1.15 +#include "nsXPCOM.h" 1.16 + 1.17 +class nsRunner : public nsIRunnable { 1.18 +public: 1.19 + NS_DECL_THREADSAFE_ISUPPORTS 1.20 + 1.21 + NS_IMETHOD Run() { 1.22 + nsCOMPtr<nsIThread> thread; 1.23 + nsresult rv = NS_GetCurrentThread(getter_AddRefs(thread)); 1.24 + if (NS_FAILED(rv)) { 1.25 + printf("failed to get current thread\n"); 1.26 + return rv; 1.27 + } 1.28 + printf("running %d on thread %p\n", mNum, (void *)thread.get()); 1.29 + 1.30 + // if we don't do something slow, we'll never see the other 1.31 + // worker threads run 1.32 + PR_Sleep(PR_MillisecondsToInterval(100)); 1.33 + 1.34 + return rv; 1.35 + } 1.36 + 1.37 + nsRunner(int num) : mNum(num) { 1.38 + } 1.39 + 1.40 +protected: 1.41 + int mNum; 1.42 +}; 1.43 + 1.44 +NS_IMPL_ISUPPORTS(nsRunner, nsIRunnable) 1.45 + 1.46 +nsresult 1.47 +TestThreads() 1.48 +{ 1.49 + nsresult rv; 1.50 + 1.51 + nsCOMPtr<nsIRunnable> event = new nsRunner(0); 1.52 + if (!event) 1.53 + return NS_ERROR_OUT_OF_MEMORY; 1.54 + 1.55 + nsCOMPtr<nsIThread> runner; 1.56 + rv = NS_NewThread(getter_AddRefs(runner), event); 1.57 + if (NS_FAILED(rv)) { 1.58 + printf("failed to create thread\n"); 1.59 + return rv; 1.60 + } 1.61 + 1.62 + nsCOMPtr<nsIThread> thread; 1.63 + rv = NS_GetCurrentThread(getter_AddRefs(thread)); 1.64 + if (NS_FAILED(rv)) { 1.65 + printf("failed to get current thread\n"); 1.66 + return rv; 1.67 + } 1.68 + 1.69 + rv = runner->Shutdown(); // wait for the runner to die before quitting 1.70 + if (NS_FAILED(rv)) { 1.71 + printf("join failed\n"); 1.72 + } 1.73 + 1.74 + PR_Sleep(PR_MillisecondsToInterval(100)); // hopefully the runner will quit here 1.75 + 1.76 + return NS_OK; 1.77 +} 1.78 + 1.79 +class nsStressRunner : public nsIRunnable { 1.80 +public: 1.81 + NS_DECL_THREADSAFE_ISUPPORTS 1.82 + 1.83 + NS_IMETHOD Run() { 1.84 + NS_ASSERTION(!mWasRun, "run twice!"); 1.85 + mWasRun = true; 1.86 + PR_Sleep(1); 1.87 + if (!PR_AtomicDecrement(&gNum)) { 1.88 + printf(" last thread was %d\n", mNum); 1.89 + } 1.90 + return NS_OK; 1.91 + } 1.92 + 1.93 + nsStressRunner(int num) : mNum(num), mWasRun(false) { 1.94 + PR_AtomicIncrement(&gNum); 1.95 + } 1.96 + 1.97 + static int32_t GetGlobalCount() {return gNum;} 1.98 + 1.99 +private: 1.100 + ~nsStressRunner() { 1.101 + NS_ASSERTION(mWasRun, "never run!"); 1.102 + } 1.103 + 1.104 +protected: 1.105 + static int32_t gNum; 1.106 + int32_t mNum; 1.107 + bool mWasRun; 1.108 +}; 1.109 + 1.110 +int32_t nsStressRunner::gNum = 0; 1.111 + 1.112 +NS_IMPL_ISUPPORTS(nsStressRunner, nsIRunnable) 1.113 + 1.114 +static int Stress(int loops, int threads) 1.115 +{ 1.116 + 1.117 + for (int i = 0; i < loops; i++) { 1.118 + printf("Loop %d of %d\n", i+1, loops); 1.119 + 1.120 + int k; 1.121 + nsIThread** array = new nsIThread*[threads]; 1.122 + NS_ASSERTION(array, "out of memory"); 1.123 + 1.124 + NS_ASSERTION(!nsStressRunner::GetGlobalCount(), "bad count of runnables"); 1.125 + 1.126 + for (k = 0; k < threads; k++) { 1.127 + nsCOMPtr<nsIThread> t; 1.128 + nsresult rv = NS_NewThread(getter_AddRefs(t), new nsStressRunner(k)); 1.129 + if (NS_FAILED(rv)) { 1.130 + NS_ERROR("can't create thread"); 1.131 + return -1; 1.132 + } 1.133 + NS_ADDREF(array[k] = t); 1.134 + } 1.135 + 1.136 + for (k = threads-1; k >= 0; k--) { 1.137 + array[k]->Shutdown(); 1.138 + NS_RELEASE(array[k]); 1.139 + } 1.140 + delete [] array; 1.141 + } 1.142 + return 0; 1.143 +} 1.144 + 1.145 +static void threadProc(void *arg) 1.146 +{ 1.147 + // printf(" running thread %d\n", (int) arg); 1.148 + PR_Sleep(1); 1.149 + PR_ASSERT(PR_JOINABLE_THREAD == PR_GetThreadState(PR_GetCurrentThread())); 1.150 +} 1.151 + 1.152 +static int StressNSPR(int loops, int threads) 1.153 +{ 1.154 + 1.155 + for (int i = 0; i < loops; i++) { 1.156 + printf("Loop %d of %d\n", i+1, loops); 1.157 + 1.158 + int k; 1.159 + PRThread** array = new PRThread*[threads]; 1.160 + PR_ASSERT(array); 1.161 + 1.162 + for (k = 0; k < threads; k++) { 1.163 + array[k] = PR_CreateThread(PR_USER_THREAD, 1.164 + threadProc, (void*) k, 1.165 + PR_PRIORITY_NORMAL, 1.166 + PR_GLOBAL_THREAD, 1.167 + PR_JOINABLE_THREAD, 1.168 + 0); 1.169 + PR_ASSERT(array[k]); 1.170 + } 1.171 + 1.172 + for (k = 0; k < threads; k++) { 1.173 + PR_ASSERT(PR_JOINABLE_THREAD == PR_GetThreadState(array[k])); 1.174 + } 1.175 + 1.176 + for (k = threads-1; k >= 0; k--) { 1.177 + PR_JoinThread(array[k]); 1.178 + } 1.179 + delete [] array; 1.180 + } 1.181 + return 0; 1.182 +} 1.183 + 1.184 + 1.185 +int 1.186 +main(int argc, char** argv) 1.187 +{ 1.188 + int retval = 0; 1.189 + nsresult rv; 1.190 + 1.191 + rv = NS_InitXPCOM2(nullptr, nullptr, nullptr); 1.192 + if (NS_FAILED(rv)) return -1; 1.193 + 1.194 + if (argc > 1 && !strcmp(argv[1], "-stress")) { 1.195 + int loops; 1.196 + int threads; 1.197 + if (argc != 4 || *argv[2] != '-' || *argv[3] != '-' || 1.198 + !(loops = atoi(argv[2]+1)) || !(threads = atoi(argv[3]+1))) { 1.199 + printf("To use -stress you must pass loop count and thread count...\n" 1.200 + " TestThreads -stress -1000 -50\n"); 1.201 + } else { 1.202 + printf("Running stress test with %d loops of %d threads each\n", 1.203 + loops, threads); 1.204 + retval = Stress(loops, threads); 1.205 + } 1.206 + } else if (argc > 1 && !strcmp(argv[1], "-stress-nspr")) { 1.207 + int loops; 1.208 + int threads; 1.209 + if (argc != 4 || *argv[2] != '-' || *argv[3] != '-' || 1.210 + !(loops = atoi(argv[2]+1)) || !(threads = atoi(argv[3]+1))) { 1.211 + printf("To use -stress-nspr you must pass loop count and thread count...\n" 1.212 + " TestThreads -stress -1000 -50\n"); 1.213 + } else { 1.214 + printf("Running stress test with %d loops of %d threads each\n", 1.215 + loops, threads); 1.216 + retval = StressNSPR(loops, threads); 1.217 + } 1.218 + } else { 1.219 + rv = TestThreads(); 1.220 + if (NS_FAILED(rv)) return -1; 1.221 + } 1.222 + 1.223 + rv = NS_ShutdownXPCOM(nullptr); 1.224 + if (NS_FAILED(rv)) return -1; 1.225 + return retval; 1.226 +}