lockfile.c (6939B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* 7 ** File: lockfile.c 8 ** Purpose: test basic locking functions 9 ** Just because this times stuff, don't think its a perforamnce 10 ** test!!! 11 ** 12 ** Modification History: 13 ** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. 14 ** The debug mode will print all of the printfs associated with this 15 *test. 16 ** The regress mode will be the default mode. Since the regress tool 17 *limits 18 ** the output to a one line status:PASS or FAIL,all of the printf 19 *statements 20 ** have been handled with an if (debug_mode) statement. 21 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been 22 *updated to 23 ** recognize the return code from tha main program. 24 ***********************************************************************/ 25 /*********************************************************************** 26 ** Includes 27 ***********************************************************************/ 28 /* Used to get the command line option */ 29 #include "plgetopt.h" 30 31 #include "prcmon.h" 32 #include "prerror.h" 33 #include "prinit.h" 34 #include "prinrval.h" 35 #include "prlock.h" 36 #include "prlog.h" 37 #include "prmon.h" 38 #include "prthread.h" 39 #include "prtypes.h" 40 41 #include "private/pprio.h" 42 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 47 PRIntn failed_already = 0; 48 PRIntn debug_mode; 49 50 const static PRIntervalTime contention_interval = 50; 51 52 typedef struct LockContentious_s { 53 PRLock* ml; 54 PRInt32 loops; 55 PRIntervalTime overhead; 56 PRIntervalTime interval; 57 } LockContentious_t; 58 59 #define LOCKFILE "prlock.fil" 60 61 static PRIntervalTime NonContentiousLock(PRInt32 loops) { 62 PRFileDesc* _lockfile; 63 while (loops-- > 0) { 64 _lockfile = PR_Open(LOCKFILE, PR_CREATE_FILE | PR_RDWR, 0666); 65 if (!_lockfile) { 66 if (debug_mode) 67 printf("could not create lockfile: %d [%d]\n", PR_GetError(), 68 PR_GetOSError()); 69 return PR_INTERVAL_NO_TIMEOUT; 70 } 71 PR_LockFile(_lockfile); 72 PR_UnlockFile(_lockfile); 73 PR_Close(_lockfile); 74 } 75 return 0; 76 } /* NonContentiousLock */ 77 78 static void PR_CALLBACK LockContender(void* arg) { 79 LockContentious_t* contention = (LockContentious_t*)arg; 80 PRFileDesc* _lockfile; 81 while (contention->loops-- > 0) { 82 _lockfile = PR_Open(LOCKFILE, PR_CREATE_FILE | PR_RDWR, 0666); 83 if (!_lockfile) { 84 if (debug_mode) 85 printf("could not create lockfile: %d [%d]\n", PR_GetError(), 86 PR_GetOSError()); 87 break; 88 } 89 PR_LockFile(_lockfile); 90 PR_Sleep(contention->interval); 91 PR_UnlockFile(_lockfile); 92 PR_Close(_lockfile); 93 } 94 95 } /* LockContender */ 96 97 /* 98 ** Win16 requires things passed to Threads not be on the stack 99 */ 100 static LockContentious_t contention; 101 102 static PRIntervalTime ContentiousLock(PRInt32 loops) { 103 PRStatus status; 104 PRThread* thread = NULL; 105 PRIntervalTime overhead, timein = PR_IntervalNow(); 106 107 contention.loops = loops; 108 contention.overhead = 0; 109 contention.ml = PR_NewLock(); 110 contention.interval = contention_interval; 111 thread = 112 PR_CreateThread(PR_USER_THREAD, LockContender, &contention, 113 PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); 114 PR_ASSERT(thread != NULL); 115 116 overhead = PR_IntervalNow() - timein; 117 118 while (contention.loops > 0) { 119 PR_Lock(contention.ml); 120 contention.overhead += contention.interval; 121 PR_Sleep(contention.interval); 122 PR_Unlock(contention.ml); 123 } 124 125 timein = PR_IntervalNow(); 126 status = PR_JoinThread(thread); 127 PR_DestroyLock(contention.ml); 128 overhead += (PR_IntervalNow() - timein); 129 return overhead + contention.overhead; 130 } /* ContentiousLock */ 131 132 static PRIntervalTime Test(const char* msg, 133 PRIntervalTime (*test)(PRInt32 loops), PRInt32 loops, 134 PRIntervalTime overhead) { 135 /* 136 * overhead - overhead not measured by the test. 137 * duration - wall clock time it took to perform test. 138 * predicted - extra time test says should not be counted 139 * 140 * Time accountable to the test is duration - overhead - predicted 141 * All times are Intervals and accumulated for all iterations. 142 */ 143 PRFloat64 elapsed; 144 PRIntervalTime accountable, duration; 145 PRUintn spaces = strlen(msg); 146 PRIntervalTime timeout, timein = PR_IntervalNow(); 147 PRIntervalTime predicted = test(loops); 148 timeout = PR_IntervalNow(); 149 duration = timeout - timein; 150 accountable = duration - predicted; 151 accountable -= overhead; 152 elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable); 153 if (debug_mode) { 154 printf("%s:", msg); 155 } 156 while (spaces++ < 50) 157 if (debug_mode) { 158 printf(" "); 159 } 160 if ((PRInt32)accountable < 0) { 161 if (debug_mode) { 162 printf("*****.** usecs/iteration\n"); 163 } 164 } else { 165 if (debug_mode) { 166 printf("%8.2f usecs/iteration\n", elapsed / loops); 167 } 168 } 169 return duration; 170 } /* Test */ 171 172 int main(int argc, char** argv) { 173 PRIntervalTime duration; 174 PRUint32 cpu, cpus = 2; 175 PRInt32 loops = 100; 176 177 /* The command line argument: -d is used to determine if the test is being run 178 in debug mode. The regress tool requires only one line output:PASS or FAIL. 179 All of the printfs associated with this test has been handled with a if 180 (debug_mode) test. Usage: test_name -d 181 */ 182 PLOptStatus os; 183 PLOptState* opt = PL_CreateOptState(argc, argv, "d:"); 184 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 185 if (PL_OPT_BAD == os) { 186 continue; 187 } 188 switch (opt->option) { 189 case 'd': /* debug mode */ 190 debug_mode = 1; 191 break; 192 default: 193 break; 194 } 195 } 196 PL_DestroyOptState(opt); 197 198 /* main test */ 199 200 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); 201 202 if (argc > 1) { 203 loops = atoi(argv[1]); 204 } 205 if (loops == 0) { 206 loops = 100; 207 } 208 if (debug_mode) { 209 printf("Lock: Using %d loops\n", loops); 210 } 211 212 cpus = (argc < 3) ? 2 : atoi(argv[2]); 213 if (cpus == 0) { 214 cpus = 2; 215 } 216 if (debug_mode) { 217 printf("Lock: Using %d cpu(s)\n", cpus); 218 } 219 220 for (cpu = 1; cpu <= cpus; ++cpu) { 221 if (debug_mode) { 222 printf("\nLockFile: Using %d CPU(s)\n", cpu); 223 } 224 PR_SetConcurrency(cpu); 225 226 duration = Test("LockFile non-contentious locking/unlocking", 227 NonContentiousLock, loops, 0); 228 (void)Test("LockFile contentious locking/unlocking", ContentiousLock, loops, 229 duration); 230 } 231 232 PR_Delete(LOCKFILE); /* try to get rid of evidence */ 233 234 if (debug_mode) { 235 printf("%s: test %s\n", "Lock(mutex) test", 236 ((failed_already) ? "failed" : "passed")); 237 } 238 if (failed_already) { 239 return 1; 240 } else { 241 return 0; 242 } 243 } /* main */ 244 245 /* testlock.c */