Back to index

lightning-sunbird  0.9+nobinonly
TestThreads.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsIThread.h"
00040 #include "nsIRunnable.h"
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include "nspr.h"
00044 #include "nsCOMPtr.h"
00045 #include "nsIServiceManager.h"
00046 
00047 class nsRunner : public nsIRunnable {
00048 public:
00049     NS_DECL_ISUPPORTS
00050 
00051     NS_IMETHOD Run() {
00052         nsCOMPtr<nsIThread> thread;
00053         nsresult rv = nsIThread::GetCurrent(getter_AddRefs(thread));
00054         if (NS_FAILED(rv)) {
00055             printf("failed to get current thread\n");
00056             return rv;
00057         }
00058         printf("running %d on thread %p\n", mNum, (void *)thread.get());
00059 
00060         // if we don't do something slow, we'll never see the other
00061         // worker threads run
00062         PR_Sleep(PR_MillisecondsToInterval(100));
00063 
00064         return rv;
00065     }
00066 
00067     nsRunner(int num) : mNum(num) {
00068     }
00069 
00070 protected:
00071     int mNum;
00072 };
00073 
00074 NS_IMPL_THREADSAFE_ISUPPORTS1(nsRunner, nsIRunnable)
00075 
00076 nsresult
00077 TestThreads()
00078 {
00079     nsresult rv;
00080 
00081     nsCOMPtr<nsIThread> runner;
00082     rv = NS_NewThread(getter_AddRefs(runner), new nsRunner(0), 0, PR_JOINABLE_THREAD);
00083     if (NS_FAILED(rv)) {
00084         printf("failed to create thread\n");
00085         return rv;
00086     }
00087 
00088     nsCOMPtr<nsIThread> thread;
00089     rv = nsIThread::GetCurrent(getter_AddRefs(thread));
00090     if (NS_FAILED(rv)) {
00091         printf("failed to get current thread\n");
00092         return rv;
00093     }
00094 
00095     PRThreadScope scope;
00096     rv = runner->GetScope(&scope);
00097     if (NS_FAILED(rv)) {
00098         printf("runner already exited\n");        
00099     }
00100 
00101     rv = runner->Join();     // wait for the runner to die before quitting
00102     if (NS_FAILED(rv)) {
00103         printf("join failed\n");        
00104     }
00105 
00106     rv = runner->GetScope(&scope);      // this should fail after Join
00107     if (NS_SUCCEEDED(rv)) {
00108         printf("get scope failed\n");        
00109     }
00110 
00111     rv = runner->Interrupt();   // this should fail after Join
00112     if (NS_SUCCEEDED(rv)) {
00113         printf("interrupt failed\n");        
00114     }
00115 
00117     // try an unjoinable thread 
00118     rv = NS_NewThread(getter_AddRefs(runner), new nsRunner(1));
00119     if (NS_FAILED(rv)) {
00120         printf("failed to create thread\n");
00121         return rv;
00122     }
00123 
00124     rv = runner->Join();     // wait for the runner to die before quitting
00125     if (NS_SUCCEEDED(rv)) {
00126         printf("shouldn't have been able to join an unjoinable thread\n");        
00127     }
00128 
00129     PR_Sleep(PR_MillisecondsToInterval(100));       // hopefully the runner will quit here
00130 
00131     return NS_OK;
00132 }
00133 
00134 class nsStressRunner : public nsIRunnable {
00135 public:
00136     NS_DECL_ISUPPORTS
00137 
00138     NS_IMETHOD Run() {
00139         NS_ASSERTION(!mWasRun, "run twice!");
00140         mWasRun = PR_TRUE;
00141         PR_Sleep(1);
00142         if (!PR_AtomicDecrement(&gNum)) {
00143             printf("   last thread was %d\n", mNum);
00144         }
00145         return NS_OK;
00146     }
00147 
00148     nsStressRunner(int num) : mNum(num), mWasRun(PR_FALSE) {
00149         PR_AtomicIncrement(&gNum);
00150     }
00151 
00152     static PRInt32 GetGlobalCount() {return gNum;}
00153 
00154 private:
00155     ~nsStressRunner() {
00156         NS_ASSERTION(mWasRun, "never run!");
00157     }
00158 
00159 protected:
00160     static PRInt32 gNum;
00161     PRInt32 mNum;
00162     PRBool mWasRun;
00163 };
00164 
00165 PRInt32 nsStressRunner::gNum = 0;
00166 
00167 NS_IMPL_THREADSAFE_ISUPPORTS1(nsStressRunner, nsIRunnable)
00168 
00169 static int Stress(int loops, int threads)
00170 {
00171 
00172     for (int i = 0; i < loops; i++) {
00173         printf("Loop %d of %d\n", i+1, loops);
00174 
00175         int k;
00176         nsIThread** array = new nsIThread*[threads];
00177         NS_ASSERTION(array, "out of memory");
00178 
00179         NS_ASSERTION(!nsStressRunner::GetGlobalCount(), "bad count of runnables");
00180         
00181         for (k = 0; k < threads; k++) {
00182             nsCOMPtr<nsIThread> t;
00183             nsresult rv = NS_NewThread(getter_AddRefs(t), 
00184                                        new nsStressRunner(k),
00185                                        0, PR_JOINABLE_THREAD);
00186             NS_ASSERTION(NS_SUCCEEDED(rv), "can't create thread");
00187             NS_ADDREF(array[k] = t);
00188         }
00189 
00190         for (k = threads-1; k >= 0; k--) {
00191             array[k]->Join();
00192             NS_RELEASE(array[k]);    
00193         }
00194         delete [] array;
00195     }
00196     return 0;
00197 }
00198 
00199 PR_STATIC_CALLBACK(void) threadProc(void *arg)
00200 {
00201     // printf("   running thread %d\n", (int) arg);
00202     PR_Sleep(1);
00203     PR_ASSERT(PR_JOINABLE_THREAD == PR_GetThreadState(PR_GetCurrentThread()));
00204 }
00205 
00206 static int StressNSPR(int loops, int threads)
00207 {
00208 
00209     for (int i = 0; i < loops; i++) {
00210         printf("Loop %d of %d\n", i+1, loops);
00211 
00212         int k;
00213         PRThread** array = new PRThread*[threads];
00214         PR_ASSERT(array);
00215 
00216         for (k = 0; k < threads; k++) {
00217             array[k] = PR_CreateThread(PR_USER_THREAD,
00218                                        threadProc, (void*) k,
00219                                        PR_PRIORITY_NORMAL,
00220                                        PR_GLOBAL_THREAD,
00221                                        PR_JOINABLE_THREAD,
00222                                        0);
00223             PR_ASSERT(array[k]);
00224         }                               
00225 
00226         for (k = 0; k < threads; k++) {
00227             PR_ASSERT(PR_JOINABLE_THREAD == PR_GetThreadState(array[k]));
00228         }                               
00229 
00230         for (k = threads-1; k >= 0; k--) {
00231             PR_JoinThread(array[k]);
00232         }
00233         delete [] array;
00234     }
00235     return 0;
00236 }
00237 
00238 
00239 int
00240 main(int argc, char** argv)
00241 {
00242     int retval = 0;
00243     nsresult rv;
00244     
00245     rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
00246     if (NS_FAILED(rv)) return -1;
00247 
00248     if (argc > 1 && !strcmp(argv[1], "-stress")) {
00249         int loops;
00250         int threads;
00251         if (argc != 4 || *argv[2] != '-' || *argv[3] != '-' ||
00252             !(loops = atoi(argv[2]+1)) || !(threads = atoi(argv[3]+1))) {
00253            printf("To use -stress you must pass loop count and thread count...\n"
00254                   "   TestThreads -stress -1000 -50\n");
00255         } else {
00256            printf("Running stress test with %d loops of %d threads each\n",
00257                   loops, threads);
00258            retval = Stress(loops, threads);
00259         }
00260     } else if (argc > 1 && !strcmp(argv[1], "-stress-nspr")) {
00261         int loops;
00262         int threads;
00263         if (argc != 4 || *argv[2] != '-' || *argv[3] != '-' ||
00264             !(loops = atoi(argv[2]+1)) || !(threads = atoi(argv[3]+1))) {
00265            printf("To use -stress-nspr you must pass loop count and thread count...\n"
00266                   "   TestThreads -stress -1000 -50\n");
00267         } else {
00268            printf("Running stress test with %d loops of %d threads each\n",
00269                   loops, threads);
00270            retval = StressNSPR(loops, threads);
00271         }
00272     } else {
00273         rv = TestThreads();
00274         if (NS_FAILED(rv)) return -1;
00275     }
00276 
00277     rv = NS_ShutdownXPCOM(nsnull);
00278     if (NS_FAILED(rv)) return -1;
00279     return retval;
00280 }