nsprpub/pr/tests/ntioto.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

     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/. */
     6 /*
     7 ** File: ntioto.c
     8 ** Description: 
     9 ** This test, ntioto.c, was designed to reproduce a bug reported by NES
    10 ** on WindowsNT (fibers implementation). NSPR was asserting in ntio.c
    11 ** after PR_AcceptRead() had timed out. I/O performed subsequent to the
    12 ** call to PR_AcceptRead() could complete on a CPU other than the one
    13 ** on which it was started. The assert in ntio.c detected this, then
    14 ** asserted.
    15 **
    16 ** Design:
    17 ** This test will fail with an assert in ntio.c if the problem it was
    18 ** designed to catch occurs. It returns 0 otherwise.
    19 ** 
    20 ** The main() thread initializes and tears things down. A file is
    21 ** opened for writing; this file will be written to by AcceptThread()
    22 ** and JitterThread().  Main() creates a socket for reading, listens
    23 ** and binds the socket.
    24 ** 
    25 ** ConnectThread() connects to the socket created by main, then polls
    26 ** the "state" variable. When state is AllDone, ConnectThread() exits.
    27 **
    28 ** AcceptThread() calls PR_AcceptRead() on the socket. He fully expects
    29 ** it to time out. After the timeout, AccpetThread() interacts with
    30 ** JitterThread() via a common condition variable and the state
    31 ** variable. The two threads ping-pong back and forth, each thread
    32 ** writes the the file opened by main. This should provoke the
    33 ** condition reported by NES (if we didn't fix it).
    34 **
    35 ** The failure is not solid. It may fail within a few ping-pongs between
    36 ** AcceptThread() and JitterThread() or may take a while. The default
    37 ** iteration count, jitter, is set by DEFAULT_JITTER. This may be
    38 ** modified at the command line with the -j option.
    39 ** 
    40 */
    42 #include <plgetopt.h> 
    43 #include <nspr.h> 
    44 #include <stdio.h>
    45 #include <stdlib.h>
    46 #include <string.h>
    48 /*
    49 ** Test harness infrastructure
    50 */
    51 PRLogModuleInfo *lm;
    52 PRLogModuleLevel msgLevel = PR_LOG_NONE;
    53 PRIntn  debug = 0;
    54 PRIntn  verbose = 0;
    55 PRUint32  failed_already = 0;
    56 /* end Test harness infrastructure */
    58 /* JITTER_DEFAULT: the number of times AcceptThread() and JitterThread() ping-pong */
    59 #define JITTER_DEFAULT  100000
    60 #define BASE_PORT 9867
    62 PRIntervalTime timeout;
    63 PRNetAddr   listenAddr;
    64 PRFileDesc  *listenSock;
    65 PRLock      *ml;
    66 PRCondVar   *cv;
    67 volatile enum  {
    68     RunJitter,
    69     RunAcceptRead,
    70     AllDone
    71 } state = RunAcceptRead;
    72 PRFileDesc  *file1;
    73 PRIntn  iCounter = 0;
    74 PRIntn  jitter = JITTER_DEFAULT;
    75 PRBool  resume = PR_FALSE;
    77 /*
    78 ** Emit help text for this test
    79 */
    80 static void Help( void )
    81 {
    82     printf("Template: Help(): display your help message(s) here");
    83     exit(1);
    84 } /* end Help() */
    87 /*
    88 ** static computation of PR_AcceptRead() buffer size.
    89 */
    90 #define ACCEPT_READ_DATASIZE 10
    91 #define ACCEPT_READ_BUFSIZE (PR_ACCEPT_READ_BUF_OVERHEAD + ACCEPT_READ_DATASIZE)
    93 static void AcceptThread(void *arg)
    94 {
    95     PRIntn bytesRead;
    96     char dataBuf[ACCEPT_READ_BUFSIZE];
    97     PRFileDesc  *arSock;
    98     PRNetAddr   *arAddr;
   100     bytesRead = PR_AcceptRead( listenSock, 
   101         &arSock,
   102         &arAddr,
   103         dataBuf,
   104         ACCEPT_READ_DATASIZE,
   105         PR_SecondsToInterval(1));
   107     if ( bytesRead == -1 && PR_GetError() == PR_IO_TIMEOUT_ERROR ) {
   108         if ( debug ) printf("AcceptRead timed out\n");
   109     } else {
   110         if ( debug ) printf("Oops! read: %d, error: %d\n", bytesRead, PR_GetError());
   111     }
   113     while( state != AllDone )  {
   114         PR_Lock( ml );
   115         while( state != RunAcceptRead )
   116             PR_WaitCondVar( cv, PR_INTERVAL_NO_TIMEOUT );
   117         if ( ++iCounter >= jitter )
   118             state = AllDone;
   119         else
   120             state = RunJitter;
   121         if ( verbose ) printf(".");
   122         PR_NotifyCondVar( cv );
   123         PR_Unlock( ml );
   124         PR_Write( file1, ".", 1 );
   125     }
   127     return;
   128 } /* end AcceptThread() */
   130 static void JitterThread(void *arg)
   131 {
   132     while( state != AllDone )  {
   133         PR_Lock( ml );
   134         while( state != RunJitter && state != AllDone )
   135             PR_WaitCondVar( cv, PR_INTERVAL_NO_TIMEOUT );
   136         if ( state != AllDone)
   137             state = RunAcceptRead;
   138         if ( verbose ) printf("+");
   139         PR_NotifyCondVar( cv );
   140         PR_Unlock( ml );
   141         PR_Write( file1, "+", 1 );
   142     }
   143     return;
   144 } /* end Goofy() */
   146 static void ConnectThread( void *arg )
   147 {
   148     PRStatus    rv;
   149     PRFileDesc  *clientSock;
   150     PRNetAddr   serverAddress;
   151     clientSock = PR_NewTCPSocket();
   153     PR_ASSERT(clientSock);
   155     if ( resume ) {
   156         if ( debug ) printf("pausing 3 seconds before connect\n");
   157         PR_Sleep( PR_SecondsToInterval(3));
   158     }
   160     memset(&serverAddress, 0, sizeof(serverAddress));
   161     rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &serverAddress);
   162     PR_ASSERT( PR_SUCCESS == rv );
   163     rv = PR_Connect( clientSock, 
   164         &serverAddress, 
   165         PR_SecondsToInterval(1));
   166     PR_ASSERT( PR_SUCCESS == rv );
   168     /* that's all we do. ... Wait for the acceptread() to timeout */
   169     while( state != AllDone )
   170         PR_Sleep( PR_SecondsToInterval(1));
   171     return;
   172 } /* end ConnectThread() */
   175 int main(int argc, char **argv)
   176 {
   177     PRThread *tJitter;
   178     PRThread *tAccept;
   179     PRThread *tConnect;
   180     PRStatus rv;
   181     /* This test if valid for WinNT only! */
   183 #if !defined(WINNT)
   184     return 0;
   185 #endif
   187     {
   188         /*
   189         ** Get command line options
   190         */
   191         PLOptStatus os;
   192         PLOptState *opt = PL_CreateOptState(argc, argv, "hdrvj:");
   194 	    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
   195         {
   196 		    if (PL_OPT_BAD == os) continue;
   197             switch (opt->option)
   198             {
   199             case 'd':  /* debug */
   200                 debug = 1;
   201 			    msgLevel = PR_LOG_ERROR;
   202                 break;
   203             case 'v':  /* verbose mode */
   204                 verbose = 1;
   205 			    msgLevel = PR_LOG_DEBUG;
   206                 break;
   207             case 'j':
   208                 jitter = atoi(opt->value);
   209                 if ( jitter == 0)
   210                     jitter = JITTER_DEFAULT;
   211                 break;
   212             case 'r':
   213                 resume = PR_TRUE;
   214                 break;
   215             case 'h':  /* help message */
   216 			    Help();
   217                 break;
   218              default:
   219                 break;
   220             }
   221         }
   222 	    PL_DestroyOptState(opt);
   223     }
   225     lm = PR_NewLogModule("Test");       /* Initialize logging */
   227     /* set concurrency */
   228     PR_SetConcurrency( 4 );
   230     /* setup thread synchronization mechanics */
   231     ml = PR_NewLock();
   232     cv = PR_NewCondVar( ml );
   234     /* setup a tcp socket */
   235     memset(&listenAddr, 0, sizeof(listenAddr));
   236     rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr);
   237     PR_ASSERT( PR_SUCCESS == rv );
   239     listenSock = PR_NewTCPSocket();
   240     PR_ASSERT( listenSock );
   242     rv = PR_Bind( listenSock, &listenAddr);
   243     PR_ASSERT( PR_SUCCESS == rv );
   245     rv = PR_Listen( listenSock, 5 );
   246     PR_ASSERT( PR_SUCCESS == rv );
   248     /* open a file for writing, provoke bug */
   249     file1 = PR_Open("xxxTestFile", PR_CREATE_FILE | PR_RDWR, 666);
   251     /* create Connect thread */
   252     tConnect = PR_CreateThread(
   253         PR_USER_THREAD, ConnectThread, NULL,
   254         PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
   255         PR_JOINABLE_THREAD, 0 );
   256     PR_ASSERT( tConnect );
   258     /* create jitter off thread */
   259     tJitter = PR_CreateThread(
   260         PR_USER_THREAD, JitterThread, NULL,
   261         PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
   262         PR_JOINABLE_THREAD, 0 );
   263     PR_ASSERT( tJitter );
   265     /* create acceptread thread */
   266     tAccept = PR_CreateThread(
   267         PR_USER_THREAD, AcceptThread, NULL,
   268         PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
   269         PR_JOINABLE_THREAD, 0 );
   270     PR_ASSERT( tAccept );
   272     /* wait for all threads to quit, then terminate gracefully */
   273     PR_JoinThread( tConnect );
   274     PR_JoinThread( tAccept );
   275     PR_JoinThread( tJitter );
   276     PR_Close( listenSock );
   277     PR_DestroyCondVar(cv);
   278     PR_DestroyLock(ml);
   279     PR_Close( file1 );
   280     PR_Delete( "xxxTestFile");
   282     /* test return and exit */
   283     if (debug) printf("%s\n", (failed_already)? "FAIL" : "PASS");
   284     return( (failed_already == PR_TRUE )? 1 : 0 );
   285 }  /* main() */
   286 /* end ntioto.c */

mercurial