nsprpub/pr/tests/lock.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/tests/lock.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,519 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     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 +/*
    1.10 +** File:        lock.c
    1.11 +** Purpose:     test basic locking functions
    1.12 +**
    1.13 +** Modification History:
    1.14 +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
    1.15 +**	         The debug mode will print all of the printfs associated with this test.
    1.16 +**			 The regress mode will be the default mode. Since the regress tool limits
    1.17 +**           the output to a one line status:PASS or FAIL,all of the printf statements
    1.18 +**			 have been handled with an if (debug_mode) statement.
    1.19 +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
    1.20 +**			recognize the return code from tha main program.
    1.21 +**
    1.22 +** 11-Aug-97 LarryH. Win16 port of NSPR.
    1.23 +**           - Added "PASS", "FAIL" messages on completion.
    1.24 +**           - Change stack variables to static scope variables
    1.25 +**             because of shadow-stack use by Win16
    1.26 +**           - Added PR_CALLBACK attribute to functions called by NSPR
    1.27 +**           - Added command line arguments:
    1.28 +**             - l <num> to control the number of loops
    1.29 +**             - c <num> to control the number of CPUs.
    1.30 +**             (was positional argv).
    1.31 +** 
    1.32 +**
    1.33 +***********************************************************************/
    1.34 +
    1.35 +/***********************************************************************
    1.36 +** Includes
    1.37 +***********************************************************************/
    1.38 +/* Used to get the command line option */
    1.39 +#include "plgetopt.h"
    1.40 +
    1.41 +#include "prio.h"
    1.42 +#include "prcmon.h"
    1.43 +#include "prinit.h"
    1.44 +#include "prinrval.h"
    1.45 +#include "prprf.h"
    1.46 +#include "prlock.h"
    1.47 +#include "prlog.h"
    1.48 +#include "prmon.h"
    1.49 +#include "prmem.h"
    1.50 +#include "prthread.h"
    1.51 +#include "prtypes.h"
    1.52 +
    1.53 +#include "plstr.h"
    1.54 +
    1.55 +#include <stdlib.h>
    1.56 +
    1.57 +#if defined(XP_UNIX)
    1.58 +#include <string.h>
    1.59 +#endif
    1.60 +
    1.61 +static PRIntn failed_already=0;
    1.62 +static PRFileDesc *std_err = NULL;
    1.63 +static PRBool verbosity = PR_FALSE;
    1.64 +static PRBool debug_mode = PR_FALSE;
    1.65 +
    1.66 +const static PRIntervalTime contention_interval = 50;
    1.67 +
    1.68 +typedef struct LockContentious_s {
    1.69 +    PRLock *ml;
    1.70 +    PRInt32 loops;
    1.71 +    PRUint32 contender;
    1.72 +    PRUint32 contentious;
    1.73 +    PRIntervalTime overhead;
    1.74 +    PRIntervalTime interval;
    1.75 +} LockContentious_t;
    1.76 +
    1.77 +typedef struct MonitorContentious_s {
    1.78 +    PRMonitor *ml;
    1.79 +    PRInt32 loops;
    1.80 +    PRUint32 contender;
    1.81 +    PRUint32 contentious;
    1.82 +    PRIntervalTime overhead;
    1.83 +    PRIntervalTime interval;
    1.84 +} MonitorContentious_t;
    1.85 +
    1.86 +
    1.87 +static PRIntervalTime Sleeper(PRUint32 loops)
    1.88 +{
    1.89 +    PRIntervalTime predicted = 0;
    1.90 +    while (loops-- > 0)
    1.91 +    {
    1.92 +        predicted += contention_interval;
    1.93 +        (void)PR_Sleep(contention_interval);
    1.94 +    }
    1.95 +    return predicted;
    1.96 +}  /* Sleeper */
    1.97 +
    1.98 +/*
    1.99 +** BASIC LOCKS
   1.100 +*/
   1.101 +static PRIntervalTime MakeLock(PRUint32 loops)
   1.102 +{
   1.103 +    PRLock *ml = NULL;
   1.104 +    while (loops-- > 0)
   1.105 +    {
   1.106 +        ml = PR_NewLock();
   1.107 +        PR_DestroyLock(ml);
   1.108 +        ml = NULL;
   1.109 +    }
   1.110 +    return 0;
   1.111 +}  /* MakeLock */
   1.112 +
   1.113 +static PRIntervalTime NonContentiousLock(PRUint32 loops)
   1.114 +{
   1.115 +    PRLock *ml = NULL;
   1.116 +    ml = PR_NewLock();
   1.117 +    while (loops-- > 0)
   1.118 +    {
   1.119 +        PR_Lock(ml);
   1.120 +        PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(ml);
   1.121 +        PR_Unlock(ml);
   1.122 +    }
   1.123 +    PR_DestroyLock(ml);
   1.124 +    return 0;
   1.125 +}  /* NonContentiousLock */
   1.126 +
   1.127 +static void PR_CALLBACK LockContender(void *arg)
   1.128 +{
   1.129 +    LockContentious_t *contention = (LockContentious_t*)arg;
   1.130 +    while (contention->loops-- > 0)
   1.131 +    {
   1.132 +        PR_Lock(contention->ml);
   1.133 +        PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(contention->ml);
   1.134 +        contention->contender+= 1;
   1.135 +        contention->overhead += contention->interval;
   1.136 +        PR_Sleep(contention->interval);
   1.137 +        PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(contention->ml);
   1.138 +        PR_Unlock(contention->ml);
   1.139 +    }
   1.140 +}  /* LockContender */
   1.141 +
   1.142 +static PRIntervalTime ContentiousLock(PRUint32 loops)
   1.143 +{
   1.144 +    PRStatus status;
   1.145 +    PRThread *thread = NULL;
   1.146 +    LockContentious_t * contention;
   1.147 +    PRIntervalTime rv, overhead, timein = PR_IntervalNow();
   1.148 +
   1.149 +    contention = PR_NEWZAP(LockContentious_t);
   1.150 +    contention->loops = loops;
   1.151 +    contention->overhead = 0;
   1.152 +    contention->ml = PR_NewLock();
   1.153 +    contention->interval = contention_interval;
   1.154 +    thread = PR_CreateThread(
   1.155 +        PR_USER_THREAD, LockContender, contention,
   1.156 +        PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
   1.157 +    PR_ASSERT(thread != NULL);
   1.158 +
   1.159 +    overhead = PR_IntervalNow() - timein;
   1.160 +
   1.161 +    while (contention->loops-- > 0)
   1.162 +    {
   1.163 +        PR_Lock(contention->ml);
   1.164 +        PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(contention->ml);
   1.165 +        contention->contentious+= 1;
   1.166 +        contention->overhead += contention->interval;
   1.167 +        PR_Sleep(contention->interval);
   1.168 +        PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(contention->ml);
   1.169 +        PR_Unlock(contention->ml);
   1.170 +    }
   1.171 +
   1.172 +    timein = PR_IntervalNow();
   1.173 +    status = PR_JoinThread(thread);
   1.174 +    PR_DestroyLock(contention->ml);
   1.175 +    overhead += (PR_IntervalNow() - timein);
   1.176 +    rv = overhead + contention->overhead;
   1.177 +    if (verbosity)
   1.178 +        PR_fprintf(
   1.179 +            std_err, "Access ratio: %u to %u\n",
   1.180 +            contention->contentious, contention->contender);
   1.181 +    PR_Free(contention);
   1.182 +    return rv;
   1.183 +}  /* ContentiousLock */
   1.184 +
   1.185 +/*
   1.186 +** MONITORS
   1.187 +*/
   1.188 +static PRIntervalTime MakeMonitor(PRUint32 loops)
   1.189 +{
   1.190 +    PRMonitor *ml = NULL;
   1.191 +    while (loops-- > 0)
   1.192 +    {
   1.193 +        ml = PR_NewMonitor();
   1.194 +        PR_DestroyMonitor(ml);
   1.195 +        ml = NULL;
   1.196 +    }
   1.197 +    return 0;
   1.198 +}  /* MakeMonitor */
   1.199 +
   1.200 +static PRIntervalTime NonContentiousMonitor(PRUint32 loops)
   1.201 +{
   1.202 +    PRMonitor *ml = NULL;
   1.203 +    ml = PR_NewMonitor();
   1.204 +    while (loops-- > 0)
   1.205 +    {
   1.206 +        PR_EnterMonitor(ml);
   1.207 +        PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
   1.208 +        PR_ExitMonitor(ml);
   1.209 +    }
   1.210 +    PR_DestroyMonitor(ml);
   1.211 +    return 0;
   1.212 +}  /* NonContentiousMonitor */
   1.213 +
   1.214 +static void PR_CALLBACK TryEntry(void *arg)
   1.215 +{
   1.216 +    PRMonitor *ml = (PRMonitor*)arg;
   1.217 +    if (debug_mode) PR_fprintf(std_err, "Reentrant thread created\n");
   1.218 +    PR_EnterMonitor(ml);
   1.219 +    PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
   1.220 +    if (debug_mode) PR_fprintf(std_err, "Reentrant thread acquired monitor\n");
   1.221 +    PR_ExitMonitor(ml);
   1.222 +    if (debug_mode) PR_fprintf(std_err, "Reentrant thread released monitor\n");
   1.223 +}  /* TryEntry */
   1.224 +
   1.225 +static PRIntervalTime ReentrantMonitor(PRUint32 loops)
   1.226 +{
   1.227 +    PRStatus status;
   1.228 +    PRThread *thread;
   1.229 +    PRMonitor *ml = PR_NewMonitor();
   1.230 +    if (debug_mode) PR_fprintf(std_err, "\nMonitor created for reentrant test\n");
   1.231 +
   1.232 +    PR_EnterMonitor(ml);
   1.233 +    PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
   1.234 +    PR_EnterMonitor(ml);
   1.235 +    PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
   1.236 +    if (debug_mode) PR_fprintf(std_err, "Monitor acquired twice\n");
   1.237 +
   1.238 +    thread = PR_CreateThread(
   1.239 +        PR_USER_THREAD, TryEntry, ml,
   1.240 +        PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
   1.241 +    PR_ASSERT(thread != NULL);
   1.242 +    PR_Sleep(PR_SecondsToInterval(1));
   1.243 +    PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
   1.244 +
   1.245 +    PR_ExitMonitor(ml);
   1.246 +    PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ml);
   1.247 +    if (debug_mode) PR_fprintf(std_err, "Monitor released first time\n");
   1.248 +
   1.249 +    PR_ExitMonitor(ml);
   1.250 +    if (debug_mode) PR_fprintf(std_err, "Monitor released second time\n");
   1.251 +
   1.252 +    status = PR_JoinThread(thread);
   1.253 +    if (debug_mode) PR_fprintf(std_err, 
   1.254 +        "Reentrant thread joined %s\n",
   1.255 +        (status == PR_SUCCESS) ? "successfully" : "in error");
   1.256 +
   1.257 +    PR_DestroyMonitor(ml);
   1.258 +    return 0;
   1.259 +}  /* ReentrantMonitor */
   1.260 +
   1.261 +static void PR_CALLBACK MonitorContender(void *arg)
   1.262 +{
   1.263 +    MonitorContentious_t *contention = (MonitorContentious_t*)arg;
   1.264 +    while (contention->loops-- > 0)
   1.265 +    {
   1.266 +        PR_EnterMonitor(contention->ml);
   1.267 +        PR_ASSERT_CURRENT_THREAD_IN_MONITOR(contention->ml);
   1.268 +        contention->contender+= 1;
   1.269 +        contention->overhead += contention->interval;
   1.270 +        PR_Sleep(contention->interval);
   1.271 +        PR_ASSERT_CURRENT_THREAD_IN_MONITOR(contention->ml);
   1.272 +        PR_ExitMonitor(contention->ml);
   1.273 +    }
   1.274 +}  /* MonitorContender */
   1.275 +
   1.276 +static PRUint32 ContentiousMonitor(PRUint32 loops)
   1.277 +{
   1.278 +    PRStatus status;
   1.279 +    PRThread *thread = NULL;
   1.280 +    MonitorContentious_t * contention;
   1.281 +    PRIntervalTime rv, overhead, timein = PR_IntervalNow();
   1.282 +
   1.283 +    contention = PR_NEWZAP(MonitorContentious_t);
   1.284 +    contention->loops = loops;
   1.285 +    contention->overhead = 0;
   1.286 +    contention->ml = PR_NewMonitor();
   1.287 +    contention->interval = contention_interval;
   1.288 +    thread = PR_CreateThread(
   1.289 +        PR_USER_THREAD, MonitorContender, contention,
   1.290 +        PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
   1.291 +    PR_ASSERT(thread != NULL);
   1.292 +
   1.293 +    overhead = PR_IntervalNow() - timein;
   1.294 +
   1.295 +    while (contention->loops-- > 0)
   1.296 +    {
   1.297 +        PR_EnterMonitor(contention->ml);
   1.298 +        PR_ASSERT_CURRENT_THREAD_IN_MONITOR(contention->ml);
   1.299 +        contention->contentious+= 1;
   1.300 +        contention->overhead += contention->interval;
   1.301 +        PR_Sleep(contention->interval);
   1.302 +        PR_ASSERT_CURRENT_THREAD_IN_MONITOR(contention->ml);
   1.303 +        PR_ExitMonitor(contention->ml);
   1.304 +    }
   1.305 +
   1.306 +    timein = PR_IntervalNow();
   1.307 +    status = PR_JoinThread(thread);
   1.308 +    PR_DestroyMonitor(contention->ml);
   1.309 +    overhead += (PR_IntervalNow() - timein);
   1.310 +    rv = overhead + contention->overhead;
   1.311 +    if (verbosity)
   1.312 +        PR_fprintf(
   1.313 +            std_err, "Access ratio: %u to %u\n",
   1.314 +            contention->contentious, contention->contender);
   1.315 +    PR_Free(contention);
   1.316 +    return rv;
   1.317 +}  /* ContentiousMonitor */
   1.318 +
   1.319 +/*
   1.320 +** CACHED MONITORS
   1.321 +*/
   1.322 +static PRIntervalTime NonContentiousCMonitor(PRUint32 loops)
   1.323 +{
   1.324 +    MonitorContentious_t contention;
   1.325 +    while (loops-- > 0)
   1.326 +    {
   1.327 +        PR_CEnterMonitor(&contention);
   1.328 +        PR_CExitMonitor(&contention);
   1.329 +    }
   1.330 +    return 0;
   1.331 +}  /* NonContentiousCMonitor */
   1.332 +
   1.333 +static void PR_CALLBACK Contender(void *arg)
   1.334 +{
   1.335 +    MonitorContentious_t *contention = (MonitorContentious_t*)arg;
   1.336 +    while (contention->loops-- > 0)
   1.337 +    {
   1.338 +        PR_CEnterMonitor(contention);
   1.339 +        contention->contender+= 1;
   1.340 +        contention->overhead += contention->interval;
   1.341 +        PR_Sleep(contention->interval);
   1.342 +        PR_CExitMonitor(contention);
   1.343 +    }
   1.344 +}  /* Contender */
   1.345 +
   1.346 +static PRIntervalTime ContentiousCMonitor(PRUint32 loops)
   1.347 +{
   1.348 +    PRStatus status;
   1.349 +    PRThread *thread = NULL;
   1.350 +    MonitorContentious_t * contention;
   1.351 +    PRIntervalTime overhead, timein = PR_IntervalNow();
   1.352 +
   1.353 +    contention = PR_NEWZAP(MonitorContentious_t);
   1.354 +    contention->ml = NULL;
   1.355 +    contention->loops = loops;
   1.356 +    contention->interval = contention_interval;
   1.357 +    thread = PR_CreateThread(
   1.358 +        PR_USER_THREAD, Contender, contention,
   1.359 +        PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
   1.360 +    PR_ASSERT(thread != NULL);
   1.361 +
   1.362 +    overhead = PR_IntervalNow() - timein;
   1.363 +
   1.364 +    while (contention->loops-- > 0)
   1.365 +    {
   1.366 +        PR_CEnterMonitor(contention);
   1.367 +        contention->contentious+= 1;
   1.368 +        contention->overhead += contention->interval;
   1.369 +        PR_Sleep(contention->interval);
   1.370 +        PR_CExitMonitor(contention);
   1.371 +    }
   1.372 +
   1.373 +    timein = PR_IntervalNow();
   1.374 +    status = PR_JoinThread(thread);
   1.375 +    overhead += (PR_IntervalNow() - timein);
   1.376 +    overhead += overhead + contention->overhead;
   1.377 +    if (verbosity)
   1.378 +        PR_fprintf(
   1.379 +            std_err, "Access ratio: %u to %u\n",
   1.380 +            contention->contentious, contention->contender);
   1.381 +    PR_Free(contention);
   1.382 +    return overhead;
   1.383 +}  /* ContentiousCMonitor */
   1.384 +
   1.385 +static PRIntervalTime Test(
   1.386 +    const char* msg, PRUint32 (*test)(PRUint32 loops),
   1.387 +    PRUint32 loops, PRIntervalTime overhead)
   1.388 +{ 
   1.389 +    /*
   1.390 +     * overhead - overhead not measured by the test.
   1.391 +     * duration - wall clock time it took to perform test.
   1.392 +     * predicted - extra time test says should not be counted 
   1.393 +     *
   1.394 +     * Time accountable to the test is duration - overhead - predicted
   1.395 +     * All times are Intervals and accumulated for all iterations.
   1.396 +     */
   1.397 +    PRFloat64 elapsed;
   1.398 +    PRIntervalTime accountable, duration;    
   1.399 +    PRUintn spaces = PL_strlen(msg);
   1.400 +    PRIntervalTime timeout, timein = PR_IntervalNow();
   1.401 +    PRIntervalTime predicted = test(loops);
   1.402 +    timeout = PR_IntervalNow();
   1.403 +    duration = timeout - timein;
   1.404 +
   1.405 +    if (debug_mode)
   1.406 +    {
   1.407 +        accountable = duration - predicted;
   1.408 +        accountable -= overhead;
   1.409 +        elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable);
   1.410 +        PR_fprintf(PR_STDOUT, "%s:", msg);
   1.411 +        while (spaces++ < 50) PR_fprintf(PR_STDOUT, " ");
   1.412 +        if ((PRInt32)accountable < 0)
   1.413 +            PR_fprintf(PR_STDOUT, "*****.** usecs/iteration\n");
   1.414 +        else
   1.415 +            PR_fprintf(PR_STDOUT, "%8.2f usecs/iteration\n", elapsed/loops);
   1.416 +    }
   1.417 +    return duration;
   1.418 +}  /* Test */
   1.419 +
   1.420 +int main(int argc,  char **argv)
   1.421 +{
   1.422 +    PRBool rv = PR_TRUE;
   1.423 +    PRIntervalTime duration;
   1.424 +    PRUint32 cpu, cpus = 2, loops = 100;
   1.425 +
   1.426 +	
   1.427 +    PR_STDIO_INIT();
   1.428 +    PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
   1.429 +    {
   1.430 +    	/* The command line argument: -d is used to determine if the test is being run
   1.431 +    	in debug mode. The regress tool requires only one line output:PASS or FAIL.
   1.432 +    	All of the printfs associated with this test has been handled with a if (debug_mode)
   1.433 +    	test.
   1.434 +        Command line argument -l <num> sets the number of loops.
   1.435 +        Command line argument -c <num> sets the number of cpus.
   1.436 +        Usage: lock [-d] [-l <num>] [-c <num>]
   1.437 +    	*/
   1.438 +    	PLOptStatus os;
   1.439 +    	PLOptState *opt = PL_CreateOptState(argc, argv, "dvl:c:");
   1.440 +    	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
   1.441 +        {
   1.442 +    		if (PL_OPT_BAD == os) continue;
   1.443 +            switch (opt->option)
   1.444 +            {
   1.445 +            case 'd':  /* debug mode */
   1.446 +    			debug_mode = PR_TRUE;
   1.447 +                break;
   1.448 +            case 'v':  /* debug mode */
   1.449 +    			verbosity = PR_TRUE;
   1.450 +                break;
   1.451 +            case 'l':  /* number of loops */
   1.452 +                loops = atoi(opt->value);
   1.453 +                break;
   1.454 +            case 'c':  /* number of cpus */
   1.455 +                cpus = atoi(opt->value);
   1.456 +                break;
   1.457 +             default:
   1.458 +                break;
   1.459 +            }
   1.460 +        }
   1.461 +    	PL_DestroyOptState(opt);
   1.462 +    }
   1.463 +
   1.464 + /* main test */
   1.465 +    PR_SetConcurrency(8);
   1.466 +
   1.467 +    if (loops == 0) loops = 100;
   1.468 +    if (debug_mode)
   1.469 +    {
   1.470 +        std_err = PR_STDERR;
   1.471 +        PR_fprintf(std_err, "Lock: Using %d loops\n", loops);
   1.472 +    }
   1.473 +
   1.474 +    if (cpus == 0) cpus = 2;
   1.475 +    if (debug_mode) PR_fprintf(std_err, "Lock: Using %d cpu(s)\n", cpus);
   1.476 +
   1.477 +    (void)Sleeper(10);  /* try filling in the caches */
   1.478 +
   1.479 +    for (cpu = 1; cpu <= cpus; ++cpu)
   1.480 +    {
   1.481 +        if (debug_mode) PR_fprintf(std_err, "\nLock: Using %d CPU(s)\n", cpu);
   1.482 +        PR_SetConcurrency(cpu);
   1.483 +
   1.484 +        duration = Test("Overhead of PR_Sleep", Sleeper, loops, 0);
   1.485 +        duration = 0;
   1.486 +
   1.487 +        (void)Test("Lock creation/deletion", MakeLock, loops, 0);
   1.488 +        (void)Test("Lock non-contentious locking/unlocking", NonContentiousLock, loops, 0);
   1.489 +        (void)Test("Lock contentious locking/unlocking", ContentiousLock, loops, duration);
   1.490 +        (void)Test("Monitor creation/deletion", MakeMonitor, loops, 0);
   1.491 +        (void)Test("Monitor non-contentious locking/unlocking", NonContentiousMonitor, loops, 0);
   1.492 +        (void)Test("Monitor contentious locking/unlocking", ContentiousMonitor, loops, duration);
   1.493 +
   1.494 +        (void)Test("Cached monitor non-contentious locking/unlocking", NonContentiousCMonitor, loops, 0);
   1.495 +        (void)Test("Cached monitor contentious locking/unlocking", ContentiousCMonitor, loops, duration);
   1.496 +
   1.497 +        (void)ReentrantMonitor(loops);
   1.498 +    }
   1.499 +
   1.500 +    if (debug_mode)
   1.501 +        PR_fprintf(
   1.502 +            std_err, "%s: test %s\n", "Lock(mutex) test",
   1.503 +            ((rv) ? "passed" : "failed"));
   1.504 +	else {
   1.505 +		 if (!rv)
   1.506 +			 failed_already=1;
   1.507 +	}
   1.508 +
   1.509 +	if(failed_already)	
   1.510 +	{
   1.511 +	    PR_fprintf(PR_STDOUT, "FAIL\n"); 
   1.512 +		return 1;
   1.513 +    } 
   1.514 +	else
   1.515 +    {
   1.516 +	    PR_fprintf(PR_STDOUT, "PASS\n"); 
   1.517 +		return 0;
   1.518 +    }
   1.519 +
   1.520 +}  /* main */
   1.521 +
   1.522 +/* testlock.c */

mercurial