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