home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / tests / cvar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  7.7 KB  |  316 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /***********************************************************************
  20. **  1996 - Netscape Communications Corporation
  21. **
  22. ** Name: cvar.c
  23. **
  24. ** Description: Tests Condition Variable Operations 
  25. **
  26. ** Modification History:
  27. ** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  28. **             The debug mode will print all of the printfs associated with this test.
  29. **             The regress mode will be the default mode. Since the regress tool limits
  30. **           the output to a one line status:PASS or FAIL,all of the printf statements
  31. **             have been handled with an if (debug_mode) statement.
  32. ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
  33. **            recognize the return code from tha main program.
  34. ** 12-June-97 Revert to return code 0 and 1.
  35. ***********************************************************************/
  36.  
  37. /***********************************************************************
  38. ** Includes
  39. ***********************************************************************/
  40.  
  41. #include "nspr.h"
  42.  
  43. /* Used to get the command line option */
  44. #include "plgetopt.h"
  45.  
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49.  
  50. #ifdef XP_MAC
  51. #include "prlog.h"
  52. #define printf PR_LogPrint
  53. extern void SetupMacPrintfLog(char *logFile);
  54. #endif
  55.  
  56. PRMonitor *mon;
  57. #define DEFAULT_COUNT   1000
  58. PRInt32 count = 0;
  59. PRIntn debug_mode;
  60.  
  61. #define kQSIZE    1
  62.  
  63. typedef struct {
  64.     PRLock        *bufLock;
  65.     int            startIdx;
  66.     int            numFull;
  67.     PRCondVar    *notFull;
  68.     PRCondVar    *notEmpty;
  69.     void        *data[kQSIZE];
  70. } CircBuf;
  71.  
  72. static PRBool failed = PR_FALSE;
  73.  
  74. /*
  75. ** NewCB creates and initializes a new circular buffer.
  76. */
  77. static CircBuf* NewCB(void)
  78. {
  79.     CircBuf        *cbp;
  80.     
  81.     cbp = PR_NEW(CircBuf);
  82.     if (cbp == NULL)
  83.         return (NULL);
  84.         
  85.     cbp->bufLock     = PR_NewLock();
  86.     cbp->startIdx     = 0;
  87.     cbp->numFull     = 0;
  88.     cbp->notFull    = PR_NewCondVar(cbp->bufLock);
  89.     cbp->notEmpty    = PR_NewCondVar(cbp->bufLock);
  90.     
  91.     return (cbp);
  92. }
  93.  
  94. /*
  95. ** DeleteCB frees a circular buffer.
  96. */
  97. static void DeleteCB(CircBuf *cbp)
  98. {
  99.     PR_DestroyLock(cbp->bufLock);
  100.     PR_DestroyCondVar(cbp->notFull);
  101.     PR_DestroyCondVar(cbp->notEmpty);
  102.     PR_DELETE(cbp);
  103. }
  104.  
  105.  
  106. /*
  107. ** PutCBData puts new data on the queue.  If the queue is full, it waits 
  108. ** until there is room.
  109. */
  110. static void PutCBData(CircBuf *cbp, void *data)
  111. {
  112.     PR_Lock(cbp->bufLock);
  113.     /* wait while the buffer is full */
  114.     while (cbp->numFull == kQSIZE)
  115.         PR_WaitCondVar(cbp->notFull,PR_INTERVAL_NO_TIMEOUT);
  116.     cbp->data[(cbp->startIdx + cbp->numFull) % kQSIZE] = data;
  117.     cbp->numFull += 1;
  118.     
  119.     /* let a waiting reader know that there is data */
  120.     PR_NotifyCondVar(cbp->notEmpty);
  121.     PR_Unlock(cbp->bufLock);
  122.  
  123. }
  124.  
  125.  
  126. /*
  127. ** GetCBData gets the oldest data on the queue.  If the queue is empty, it waits 
  128. ** until new data appears.
  129. */
  130. static void* GetCBData(CircBuf *cbp)
  131. {
  132.     void *data;
  133.     
  134.     PR_Lock(cbp->bufLock);
  135.     /* wait while the buffer is empty */
  136.     while (cbp->numFull == 0)
  137.         PR_WaitCondVar(cbp->notEmpty,PR_INTERVAL_NO_TIMEOUT);
  138.     data = cbp->data[cbp->startIdx];
  139.     cbp->startIdx =(cbp->startIdx + 1) % kQSIZE;
  140.     cbp->numFull -= 1;
  141.     
  142.     /* let a waiting writer know that there is room */
  143.     PR_NotifyCondVar(cbp->notFull);
  144.     PR_Unlock(cbp->bufLock);
  145.     
  146.     return (data);
  147. }
  148.  
  149.  
  150. /************************************************************************/
  151.  
  152. static int alive;
  153.  
  154. static void PR_CALLBACK CXReader(void *arg)
  155. {
  156.     CircBuf *cbp = (CircBuf *)arg;
  157.     PRInt32 i, n;
  158.     void *data;
  159.  
  160.     n = count / 2;
  161.     for (i = 0; i < n; i++) {
  162.         data = GetCBData(cbp);
  163.         if ((int)data != i)
  164.             if (debug_mode) printf("data mismatch at for i = %d usec\n", i);
  165.     }
  166.  
  167.     PR_EnterMonitor(mon);
  168.     --alive;
  169.     PR_Notify(mon);
  170.     PR_ExitMonitor(mon);
  171. }
  172.  
  173. static void PR_CALLBACK CXWriter(void *arg)
  174. {
  175.     CircBuf *cbp = (CircBuf *)arg;
  176.     PRInt32 i, n;
  177.  
  178.     n = count / 2;
  179.     for (i = 0; i < n; i++)
  180.         PutCBData(cbp, (void *)i);
  181.  
  182.     PR_EnterMonitor(mon);
  183.     --alive;
  184.     PR_Notify(mon);
  185.     PR_ExitMonitor(mon);
  186. }
  187.  
  188. static void CondWaitContextSwitch(PRThreadScope scope1, PRThreadScope scope2)
  189. {
  190.     PRThread *t1, *t2;
  191.     CircBuf *cbp;
  192.  
  193.     PR_EnterMonitor(mon);
  194.  
  195.     alive = 2;
  196.  
  197.     cbp =  NewCB();
  198.  
  199.     t1 = PR_CreateThread(PR_USER_THREAD,
  200.                       CXReader, cbp, 
  201.                       PR_PRIORITY_NORMAL,
  202.                       scope1,
  203.                       PR_UNJOINABLE_THREAD,
  204.                       0);
  205.     PR_ASSERT(t1);
  206.     t2 = PR_CreateThread(PR_USER_THREAD,
  207.                       CXWriter, cbp, 
  208.                       PR_PRIORITY_NORMAL,
  209.                       scope2,
  210.                       PR_UNJOINABLE_THREAD,
  211.                       0);
  212.     PR_ASSERT(t2);
  213.  
  214.     /* Wait for both of the threads to exit */
  215.     while (alive) {
  216.     PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
  217.     }
  218.  
  219.     DeleteCB(cbp);
  220.  
  221.     PR_ExitMonitor(mon);
  222. }
  223.  
  224. static void CondWaitContextSwitchUU(void)
  225. {
  226.     CondWaitContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD);
  227. }
  228.  
  229. static void CondWaitContextSwitchUK(void)
  230. {
  231.     CondWaitContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD);
  232. }
  233.  
  234. static void CondWaitContextSwitchKK(void)
  235. {
  236.     CondWaitContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD);
  237. }
  238.  
  239. /************************************************************************/
  240.  
  241. static void Measure(void (*func)(void), const char *msg)
  242. {
  243.     PRIntervalTime start, stop;
  244.     double d;
  245.  
  246.     start = PR_IntervalNow();
  247.     (*func)();
  248.     stop = PR_IntervalNow();
  249.  
  250.     d = (double)PR_IntervalToMicroseconds(stop - start);
  251.  
  252.     if (debug_mode) printf("%40s: %6.2f usec\n", msg, d / count);
  253.  
  254.     if (0 ==  d) failed = PR_TRUE;
  255. }
  256.  
  257. static PRIntn PR_CALLBACK RealMain(int argc, char **argv)
  258. {
  259.     /* The command line argument: -d is used to determine if the test is being run
  260.     in debug mode. The regress tool requires only one line output:PASS or FAIL.
  261.     All of the printfs associated with this test has been handled with a if (debug_mode)
  262.     test.
  263.     Usage: test_name [-d] [-c n]
  264.     */
  265.     PLOptStatus os;
  266.     PLOptState *opt = PL_CreateOptState(argc, argv, "dc:");
  267.     while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  268.     {
  269.         if (PL_OPT_BAD == os) continue;
  270.         switch (opt->option)
  271.         {
  272.         case 'd':  /* debug mode */
  273.             debug_mode = 1;
  274.             break;
  275.         case 'c':  /* loop count */
  276.             count = atoi(opt->value);
  277.             break;
  278.          default:
  279.             break;
  280.         }
  281.     }
  282.     PL_DestroyOptState(opt);
  283.  
  284.     if (0 == count) count = DEFAULT_COUNT;
  285.  
  286. #ifdef XP_MAC
  287.     SetupMacPrintfLog("cvar.log");
  288.     debug_mode = 1;
  289. #endif
  290.  
  291.     mon = PR_NewMonitor();
  292.  
  293.     Measure(CondWaitContextSwitchUU, "cond var wait context switch- user/user");
  294.     Measure(CondWaitContextSwitchUK, "cond var wait context switch- user/kernel");
  295.     Measure(CondWaitContextSwitchKK, "cond var wait context switch- kernel/kernel");
  296.  
  297.     PR_DestroyMonitor(mon);
  298.  
  299.     if (debug_mode) printf("%s\n", (failed) ? "FAILED" : "PASSED");
  300.  
  301.     if(failed)
  302.         return 1;
  303.     else
  304.         return 0;
  305. }
  306.  
  307.  
  308. PRIntn main(PRIntn argc, char *argv[])
  309. {
  310.     PRIntn rv;
  311.     
  312.     PR_STDIO_INIT();
  313.     rv = PR_Initialize(RealMain, argc, argv, 0);
  314.     return rv;
  315. }  /* main */
  316.