Back to index

lightning-sunbird  0.9+nobinonly
cvar.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 the Netscape Portable Runtime (NSPR).
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-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /***********************************************************************
00039 **  1996 - Netscape Communications Corporation
00040 **
00041 ** Name: cvar.c
00042 **
00043 ** Description: Tests Condition Variable Operations 
00044 **
00045 ** Modification History:
00046 ** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
00047 **              The debug mode will print all of the printfs associated with this test.
00048 **                    The regress mode will be the default mode. Since the regress tool limits
00049 **           the output to a one line status:PASS or FAIL,all of the printf statements
00050 **                    have been handled with an if (debug_mode) statement.
00051 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
00052 **                   recognize the return code from tha main program.
00053 ** 12-June-97 Revert to return code 0 and 1.
00054 ***********************************************************************/
00055 
00056 /***********************************************************************
00057 ** Includes
00058 ***********************************************************************/
00059 
00060 #include "nspr.h"
00061 
00062 /* Used to get the command line option */
00063 #include "plgetopt.h"
00064 
00065 #include <stdio.h>
00066 #include <stdlib.h>
00067 #include <string.h>
00068 
00069 #ifdef XP_MAC
00070 #include "prlog.h"
00071 #define printf PR_LogPrint
00072 extern void SetupMacPrintfLog(char *logFile);
00073 #endif
00074 
00075 PRMonitor *mon;
00076 #define DEFAULT_COUNT   1000
00077 PRInt32 count = 0;
00078 PRIntn debug_mode;
00079 
00080 #define kQSIZE       1
00081 
00082 typedef struct {
00083        PRLock        *bufLock;
00084        int                  startIdx;
00085        int                  numFull;
00086        PRCondVar     *notFull;
00087        PRCondVar     *notEmpty;
00088        void          *data[kQSIZE];
00089 } CircBuf;
00090 
00091 static PRBool failed = PR_FALSE;
00092 
00093 /*
00094 ** NewCB creates and initializes a new circular buffer.
00095 */
00096 static CircBuf* NewCB(void)
00097 {
00098        CircBuf              *cbp;
00099        
00100        cbp = PR_NEW(CircBuf);
00101        if (cbp == NULL)
00102               return (NULL);
00103               
00104        cbp->bufLock  = PR_NewLock();
00105        cbp->startIdx        = 0;
00106        cbp->numFull  = 0;
00107        cbp->notFull  = PR_NewCondVar(cbp->bufLock);
00108        cbp->notEmpty = PR_NewCondVar(cbp->bufLock);
00109        
00110        return (cbp);
00111 }
00112 
00113 /*
00114 ** DeleteCB frees a circular buffer.
00115 */
00116 static void DeleteCB(CircBuf *cbp)
00117 {
00118        PR_DestroyLock(cbp->bufLock);
00119        PR_DestroyCondVar(cbp->notFull);
00120        PR_DestroyCondVar(cbp->notEmpty);
00121        PR_DELETE(cbp);
00122 }
00123 
00124 
00125 /*
00126 ** PutCBData puts new data on the queue.  If the queue is full, it waits 
00127 ** until there is room.
00128 */
00129 static void PutCBData(CircBuf *cbp, void *data)
00130 {
00131        PR_Lock(cbp->bufLock);
00132        /* wait while the buffer is full */
00133        while (cbp->numFull == kQSIZE)
00134               PR_WaitCondVar(cbp->notFull,PR_INTERVAL_NO_TIMEOUT);
00135        cbp->data[(cbp->startIdx + cbp->numFull) % kQSIZE] = data;
00136        cbp->numFull += 1;
00137        
00138        /* let a waiting reader know that there is data */
00139        PR_NotifyCondVar(cbp->notEmpty);
00140        PR_Unlock(cbp->bufLock);
00141 
00142 }
00143 
00144 
00145 /*
00146 ** GetCBData gets the oldest data on the queue.  If the queue is empty, it waits 
00147 ** until new data appears.
00148 */
00149 static void* GetCBData(CircBuf *cbp)
00150 {
00151        void *data;
00152        
00153        PR_Lock(cbp->bufLock);
00154        /* wait while the buffer is empty */
00155        while (cbp->numFull == 0)
00156               PR_WaitCondVar(cbp->notEmpty,PR_INTERVAL_NO_TIMEOUT);
00157        data = cbp->data[cbp->startIdx];
00158        cbp->startIdx =(cbp->startIdx + 1) % kQSIZE;
00159        cbp->numFull -= 1;
00160        
00161        /* let a waiting writer know that there is room */
00162        PR_NotifyCondVar(cbp->notFull);
00163        PR_Unlock(cbp->bufLock);
00164        
00165        return (data);
00166 }
00167 
00168 
00169 /************************************************************************/
00170 
00171 static int alive;
00172 
00173 static void PR_CALLBACK CXReader(void *arg)
00174 {
00175        CircBuf *cbp = (CircBuf *)arg;
00176     PRInt32 i, n;
00177     void *data;
00178 
00179     n = count / 2;
00180     for (i = 0; i < n; i++) {
00181               data = GetCBData(cbp);
00182               if ((int)data != i)
00183               if (debug_mode) printf("data mismatch at for i = %d usec\n", i);
00184     }
00185  
00186     PR_EnterMonitor(mon);
00187     --alive;
00188     PR_Notify(mon);
00189     PR_ExitMonitor(mon);
00190 }
00191 
00192 static void PR_CALLBACK CXWriter(void *arg)
00193 {
00194        CircBuf *cbp = (CircBuf *)arg;
00195     PRInt32 i, n;
00196 
00197     n = count / 2;
00198     for (i = 0; i < n; i++)
00199               PutCBData(cbp, (void *)i);
00200 
00201     PR_EnterMonitor(mon);
00202     --alive;
00203     PR_Notify(mon);
00204     PR_ExitMonitor(mon);
00205 }
00206 
00207 static void CondWaitContextSwitch(PRThreadScope scope1, PRThreadScope scope2)
00208 {
00209     PRThread *t1, *t2;
00210        CircBuf *cbp;
00211 
00212     PR_EnterMonitor(mon);
00213 
00214     alive = 2;
00215 
00216        cbp =  NewCB();
00217 
00218        t1 = PR_CreateThread(PR_USER_THREAD,
00219                                   CXReader, cbp, 
00220                                   PR_PRIORITY_NORMAL,
00221                                   scope1,
00222                               PR_UNJOINABLE_THREAD,
00223                                   0);
00224        PR_ASSERT(t1);
00225        t2 = PR_CreateThread(PR_USER_THREAD,
00226                                   CXWriter, cbp, 
00227                                   PR_PRIORITY_NORMAL,
00228                                   scope2,
00229                               PR_UNJOINABLE_THREAD,
00230                                   0);
00231        PR_ASSERT(t2);
00232 
00233     /* Wait for both of the threads to exit */
00234     while (alive) {
00235        PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
00236     }
00237 
00238        DeleteCB(cbp);
00239 
00240     PR_ExitMonitor(mon);
00241 }
00242 
00243 static void CondWaitContextSwitchUU(void)
00244 {
00245     CondWaitContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
00246 }
00247 
00248 static void CondWaitContextSwitchUK(void)
00249 {
00250     CondWaitContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
00251 }
00252 
00253 static void CondWaitContextSwitchKK(void)
00254 {
00255     CondWaitContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
00256 }
00257 
00258 /************************************************************************/
00259 
00260 static void Measure(void (*func)(void), const char *msg)
00261 {
00262     PRIntervalTime start, stop;
00263     double d;
00264 
00265     start = PR_IntervalNow();
00266     (*func)();
00267     stop = PR_IntervalNow();
00268 
00269     d = (double)PR_IntervalToMicroseconds(stop - start);
00270 
00271     if (debug_mode) printf("%40s: %6.2f usec\n", msg, d / count);
00272 
00273     if (0 ==  d) failed = PR_TRUE;
00274 }
00275 
00276 static PRIntn PR_CALLBACK RealMain(int argc, char **argv)
00277 {
00278        /* The command line argument: -d is used to determine if the test is being run
00279        in debug mode. The regress tool requires only one line output:PASS or FAIL.
00280        All of the printfs associated with this test has been handled with a if (debug_mode)
00281        test.
00282        Usage: test_name [-d] [-c n]
00283        */
00284        PLOptStatus os;
00285        PLOptState *opt = PL_CreateOptState(argc, argv, "dc:");
00286        while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00287     {
00288               if (PL_OPT_BAD == os) continue;
00289         switch (opt->option)
00290         {
00291         case 'd':  /* debug mode */
00292                      debug_mode = 1;
00293             break;
00294         case 'c':  /* loop count */
00295             count = atoi(opt->value);
00296             break;
00297          default:
00298             break;
00299         }
00300     }
00301        PL_DestroyOptState(opt);
00302 
00303     if (0 == count) count = DEFAULT_COUNT;
00304 
00305 #ifdef XP_MAC
00306        SetupMacPrintfLog("cvar.log");
00307        debug_mode = 1;
00308 #endif
00309 
00310     mon = PR_NewMonitor();
00311 
00312     Measure(CondWaitContextSwitchUU, "cond var wait context switch- user/user");
00313     Measure(CondWaitContextSwitchUK, "cond var wait context switch- user/kernel");
00314     Measure(CondWaitContextSwitchKK, "cond var wait context switch- kernel/kernel");
00315 
00316        PR_DestroyMonitor(mon);
00317 
00318        if (debug_mode) printf("%s\n", (failed) ? "FAILED" : "PASSED");
00319 
00320        if(failed)
00321               return 1;
00322        else
00323               return 0;
00324 }
00325 
00326 
00327 PRIntn main(PRIntn argc, char *argv[])
00328 {
00329     PRIntn rv;
00330     
00331     PR_STDIO_INIT();
00332     rv = PR_Initialize(RealMain, argc, argv, 0);
00333     return rv;
00334 }  /* main */