Back to index

lightning-sunbird  0.9+nobinonly
nameshm1.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 ** File: nameshm1.c -- Test Named Shared Memory
00040 **
00041 ** Description: 
00042 ** nameshm1 tests Named Shared Memory. nameshm1 performs two tests of
00043 ** named shared memory. 
00044 ** 
00045 ** The first test is a basic test. The basic test operates as a single
00046 ** process. The process exercises all the API elements of the facility.
00047 ** This test also attempts to write to all locations in the shared
00048 ** memory.
00049 **
00050 ** The second test is a client-server test. The client-server test
00051 ** creates a new instance of nameshm1, passing the -C argument to the
00052 ** new process; this creates the client-side process. The server-side
00053 ** (the instance of nameshm1 created from the command line) and the
00054 ** client-side interact via inter-process semaphores to verify that the
00055 ** shared memory segment can be read and written by both sides in a
00056 ** synchronized maner.
00057 **
00058 ** Note: Because this test runs in two processes, the log files created
00059 ** by the test are not in chronological sequence; makes it hard to read.
00060 ** As a temporary circumvention, I changed the definition(s) of the
00061 ** _PUT_LOG() macro in prlog.c to force a flushall(), or equivalent.
00062 ** This causes the log entries to be emitted in true chronological
00063 ** order.
00064 **
00065 ** Synopsis: nameshm1 [options] [name]
00066 ** 
00067 ** Options:
00068 ** -d       Enables debug trace via PR_LOG()
00069 ** -v       Enables verbose mode debug trace via PR_LOG()
00070 ** -w       Causes the basic test to attempt to write to the segment
00071 **          mapped as read-only. When this option is specified, the
00072 **          test should crash with a seg-fault; this is a destructive
00073 **          test and is considered successful when it seg-faults.
00074 ** 
00075 ** -C       Causes nameshm1 to start as the client-side of a
00076 **          client-server pair of processes. Only the instance
00077 **          of nameshm1 operating as the server-side process should
00078 **          specify the -C option when creating the client-side process;
00079 **          the -C option should not be specified at the command line.
00080 **          The client-side uses the shared memory segment created by
00081 **          the server-side to communicate with the server-side
00082 **          process.
00083 **          
00084 ** -p <n>   Specify the number of iterations the client-server tests
00085 **          should perform. Default: 1000.
00086 **
00087 ** -s <n>   Size, in KBytes (1024), of the shared memory segment.
00088 **          Default: (10 * 1024)
00089 **
00090 ** -i <n>   Number of client-side iterations. Default: 3
00091 **
00092 ** name     specifies the name of the shared memory segment to be used.
00093 **          Default: /tmp/xxxNSPRshm
00094 **
00095 **
00096 ** See also: prshm.h
00097 **
00098 ** /lth. Aug-1999.
00099 */
00100 
00101 #include <plgetopt.h> 
00102 #include <nspr.h>
00103 #include <stdlib.h>
00104 #include <string.h>
00105 #include <private/primpl.h>
00106 
00107 #define SEM_NAME1 "/tmp/nameshmSEM1"
00108 #define SEM_NAME2 "/tmp/nameshmSEM2"
00109 #define SEM_MODE  0666
00110 #define SHM_MODE  0666
00111 
00112 #define NameSize (1024)
00113 
00114 PRIntn  debug = 0;
00115 PRIntn  failed_already = 0;
00116 PRLogModuleLevel msgLevel = PR_LOG_NONE;
00117 PRLogModuleInfo *lm;
00118 
00119 /* command line options */
00120 PRIntn      optDebug = 0;
00121 PRIntn      optVerbose = 0;
00122 PRUint32    optWriteRO = 0;     /* test write to read-only memory. should crash  */
00123 PRUint32    optClient = 0;
00124 PRUint32    optCreate = 1;
00125 PRUint32    optAttachRW = 1;
00126 PRUint32    optAttachRO = 1;
00127 PRUint32    optClose = 1;
00128 PRUint32    optDelete = 1;
00129 PRInt32     optPing = 1000;
00130 PRUint32    optSize = (10 * 1024 );
00131 PRInt32     optClientIterations = 3;
00132 char        optName[NameSize] = "/tmp/xxxNSPRshm";
00133 
00134 char buf[1024] = "";
00135 
00136 
00137 static void BasicTest( void ) 
00138 {
00139     PRSharedMemory  *shm;
00140     char *addr; /* address of shared memory segment */
00141     PRUint32  i;
00142     PRInt32 rc;
00143 
00144     PR_LOG( lm, msgLevel,
00145              ( "nameshm1: Begin BasicTest" ));
00146 
00147     if ( PR_FAILURE == PR_DeleteSharedMemory( optName )) {
00148         PR_LOG( lm, msgLevel,
00149             ("nameshm1: Initial PR_DeleteSharedMemory() failed. No problem"));
00150     } else
00151         PR_LOG( lm, msgLevel,
00152             ("nameshm1: Initial PR_DeleteSharedMemory() success"));
00153 
00154 
00155     shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE );
00156     if ( NULL == shm )
00157     {
00158         PR_LOG( lm, msgLevel,
00159                  ( "nameshm1: RW Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00160         failed_already = 1;
00161         return;
00162     }
00163     PR_LOG( lm, msgLevel,
00164              ( "nameshm1: RW Create: success: %p", shm ));
00165 
00166     addr = PR_AttachSharedMemory( shm , 0 );
00167     if ( NULL == addr ) 
00168     {
00169         PR_LOG( lm, msgLevel,
00170                  ( "nameshm1: RW Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00171         failed_already = 1;
00172         return;
00173     }
00174     PR_LOG( lm, msgLevel,
00175              ( "nameshm1: RW Attach: success: %p", addr ));
00176 
00177     /* fill memory with i */
00178     for ( i = 0; i < optSize ;  i++ )
00179     {
00180          *(addr + i) = i;
00181     }
00182 
00183     rc = PR_DetachSharedMemory( shm, addr );
00184     if ( PR_FAILURE == rc )
00185     {
00186         PR_LOG( lm, msgLevel,
00187                  ( "nameshm1: RW Detach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00188         failed_already = 1;
00189         return;
00190     }
00191     PR_LOG( lm, msgLevel,
00192              ( "nameshm1: RW Detach: success: " ));
00193 
00194     rc = PR_CloseSharedMemory( shm );
00195     if ( PR_FAILURE == rc )
00196     {
00197         PR_LOG( lm, msgLevel,
00198                  ( "nameshm1: RW Close: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00199         failed_already = 1;
00200         return;
00201     }
00202     PR_LOG( lm, msgLevel,
00203              ( "nameshm1: RW Close: success: " ));
00204 
00205     rc = PR_DeleteSharedMemory( optName );
00206     if ( PR_FAILURE == rc )
00207     {
00208         PR_LOG( lm, msgLevel,
00209                  ( "nameshm1: RW Delete: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00210         failed_already = 1;
00211         return;
00212     }
00213     PR_LOG( lm, msgLevel,
00214              ( "nameshm1: RW Delete: success: " ));
00215 
00216     PR_LOG( lm, msgLevel,
00217             ("nameshm1: BasicTest(): Passed"));
00218 
00219     return;
00220 } /* end BasicTest() */
00221 
00222 static void ReadOnlyTest( void )
00223 {
00224     PRSharedMemory  *shm;
00225     char *roAddr; /* read-only address of shared memory segment */
00226     PRInt32 rc;
00227 
00228     PR_LOG( lm, msgLevel,
00229              ( "nameshm1: Begin ReadOnlyTest" ));
00230 
00231     shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE);
00232     if ( NULL == shm )
00233     {
00234         PR_LOG( lm, msgLevel,
00235                  ( "nameshm1: RO Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00236         failed_already = 1;
00237         return;
00238     }
00239     PR_LOG( lm, msgLevel,
00240              ( "nameshm1: RO Create: success: %p", shm ));
00241 
00242 
00243     roAddr = PR_AttachSharedMemory( shm , PR_SHM_READONLY );
00244     if ( NULL == roAddr ) 
00245     {
00246         PR_LOG( lm, msgLevel,
00247                  ( "nameshm1: RO Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00248         failed_already = 1;
00249         return;
00250     }
00251     PR_LOG( lm, msgLevel,
00252              ( "nameshm1: RO Attach: success: %p", roAddr ));
00253 
00254     if ( optWriteRO )
00255     {
00256         *roAddr = 0x00; /* write to read-only memory */
00257         failed_already = 1;
00258         PR_LOG( lm, msgLevel, ("nameshm1: Wrote to read-only memory segment!"));
00259         return;
00260     }
00261 
00262     rc = PR_DetachSharedMemory( shm, roAddr );
00263     if ( PR_FAILURE == rc )
00264     {
00265         PR_LOG( lm, msgLevel,
00266                  ( "nameshm1: RO Detach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00267         failed_already = 1;
00268         return;
00269     }
00270     PR_LOG( lm, msgLevel,
00271              ( "nameshm1: RO Detach: success: " ));
00272 
00273     rc = PR_CloseSharedMemory( shm );
00274     if ( PR_FAILURE == rc )
00275     {
00276         PR_LOG( lm, msgLevel,
00277                  ( "nameshm1: RO Close: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00278         failed_already = 1;
00279         return;
00280     }
00281     PR_LOG( lm, msgLevel,
00282              ( "nameshm1: RO Close: success: " ));
00283 
00284     rc = PR_DeleteSharedMemory( optName );
00285     if ( PR_FAILURE == rc )
00286     {
00287         PR_LOG( lm, msgLevel,
00288                  ( "nameshm1: RO Destroy: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00289         failed_already = 1;
00290         return;
00291     }
00292     PR_LOG( lm, msgLevel,
00293              ( "nameshm1: RO Destroy: success: " ));
00294 
00295     PR_LOG( lm, msgLevel,
00296         ("nameshm1: ReadOnlyTest(): Passed"));
00297 
00298     return;
00299 } /* end ReadOnlyTest() */
00300 
00301 static void DoClient( void )
00302 {
00303     PRStatus rc;
00304     PRSem *sem1, *sem2;
00305     PRSharedMemory  *shm;
00306     PRUint32 *addr; 
00307     PRInt32 i;
00308 
00309     PR_LOG( lm, msgLevel,
00310             ("nameshm1: DoClient(): Starting"));
00311 
00312     sem1 = PR_OpenSemaphore( SEM_NAME1, 0, 0, 0 );
00313     PR_ASSERT( sem1 );
00314 
00315     sem2 = PR_OpenSemaphore( SEM_NAME2, 0, 0, 0 );
00316     PR_ASSERT( sem1 );
00317 
00318     shm = PR_OpenSharedMemory( optName, optSize, 0, SHM_MODE );
00319     if ( NULL == shm )
00320     {
00321         PR_LOG( lm, msgLevel,
00322             ( "nameshm1: DoClient(): Create: Error: %ld. OSError: %ld", 
00323                 PR_GetError(), PR_GetOSError()));
00324         failed_already = 1;
00325         return;
00326     }
00327     PR_LOG( lm, msgLevel,
00328              ( "nameshm1: DoClient(): Create: success: %p", shm ));
00329 
00330     addr = PR_AttachSharedMemory( shm , 0 );
00331     if ( NULL == addr ) 
00332     {
00333         PR_LOG( lm, msgLevel,
00334             ( "nameshm1: DoClient(): Attach: Error: %ld. OSError: %ld", 
00335                 PR_GetError(), PR_GetOSError()));
00336         failed_already = 1;
00337         return;
00338     }
00339     PR_LOG( lm, msgLevel,
00340              ( "nameshm1: DoClient(): Attach: success: %p", addr ));
00341 
00342     PR_LOG( lm, msgLevel,
00343         ( "Client found: %s", addr));
00344 
00345     PR_Sleep(PR_SecondsToInterval(4));
00346     for ( i = 0 ; i < optPing ; i++ )
00347     {
00348         rc = PR_WaitSemaphore( sem2 );
00349         PR_ASSERT( PR_FAILURE != rc );
00350         
00351         (*addr)++;
00352         PR_ASSERT( (*addr % 2) == 0 );        
00353         if ( optVerbose )
00354             PR_LOG( lm, msgLevel,
00355                  ( "nameshm1: Client ping: %d, i: %d", *addr, i));
00356 
00357         rc = PR_PostSemaphore( sem1 );
00358         PR_ASSERT( PR_FAILURE != rc );
00359     }
00360 
00361     rc = PR_CloseSemaphore( sem1 );
00362     PR_ASSERT( PR_FAILURE != rc );
00363 
00364     rc = PR_CloseSemaphore( sem2 );
00365     PR_ASSERT( PR_FAILURE != rc );
00366 
00367     rc = PR_DetachSharedMemory( shm, addr );
00368     if ( PR_FAILURE == rc )
00369     {
00370         PR_LOG( lm, msgLevel,
00371             ( "nameshm1: DoClient(): Detach: Error: %ld. OSError: %ld", 
00372                 PR_GetError(), PR_GetOSError()));
00373         failed_already = 1;
00374         return;
00375     }
00376     PR_LOG( lm, msgLevel,
00377              ( "nameshm1: DoClient(): Detach: success: " ));
00378 
00379     rc = PR_CloseSharedMemory( shm );
00380     if ( PR_FAILURE == rc )
00381     {
00382         PR_LOG( lm, msgLevel,
00383             ( "nameshm1: DoClient(): Close: Error: %ld. OSError: %ld", 
00384                 PR_GetError(), PR_GetOSError()));
00385         failed_already = 1;
00386         return;
00387     }
00388     PR_LOG( lm, msgLevel,
00389              ( "nameshm1: DoClient(): Close: success: " ));
00390 
00391     return;
00392 }    /* end DoClient() */
00393 
00394 static void ClientServerTest( void )
00395 {
00396     PRStatus rc;
00397     PRSem *sem1, *sem2;
00398     PRProcess *proc;
00399     PRInt32 exit_status;
00400     PRSharedMemory  *shm;
00401     PRUint32 *addr; 
00402     PRInt32 i;
00403     char *child_argv[8];
00404     char buf[24];
00405 
00406     PR_LOG( lm, msgLevel,
00407              ( "nameshm1: Begin ClientServerTest" ));
00408 
00409     rc = PR_DeleteSharedMemory( optName );
00410     if ( PR_FAILURE == rc )
00411     {
00412         PR_LOG( lm, msgLevel,
00413             ( "nameshm1: Server: Destroy: failed. No problem"));
00414     } else
00415         PR_LOG( lm, msgLevel,
00416             ( "nameshm1: Server: Destroy: success" ));
00417 
00418 
00419     shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE);
00420     if ( NULL == shm )
00421     {
00422         PR_LOG( lm, msgLevel,
00423                  ( "nameshm1: Server: Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00424         failed_already = 1;
00425         return;
00426     }
00427     PR_LOG( lm, msgLevel,
00428              ( "nameshm1: Server: Create: success: %p", shm ));
00429 
00430     addr = PR_AttachSharedMemory( shm , 0 );
00431     if ( NULL == addr ) 
00432     {
00433         PR_LOG( lm, msgLevel,
00434                  ( "nameshm1: Server: Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError()));
00435         failed_already = 1;
00436         return;
00437     }
00438     PR_LOG( lm, msgLevel,
00439              ( "nameshm1: Server: Attach: success: %p", addr ));
00440 
00441     sem1 = PR_OpenSemaphore( SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 0 );
00442     PR_ASSERT( sem1 );
00443 
00444     sem2 = PR_OpenSemaphore( SEM_NAME2, PR_SEM_CREATE, SEM_MODE, 1 );
00445     PR_ASSERT( sem1 );
00446 
00447     strcpy( (char*)addr, "FooBar" );
00448 
00449     child_argv[0] = "nameshm1";
00450     child_argv[1] = "-C";
00451     child_argv[2] = "-p";
00452     sprintf( buf, "%d", optPing );
00453     child_argv[3] = buf;
00454     child_argv[4] = optName;
00455     child_argv[5] = NULL;
00456 
00457     proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL);
00458     PR_ASSERT( proc );
00459 
00460     PR_Sleep( PR_SecondsToInterval(4));
00461 
00462     *addr = 1;
00463     for ( i = 0 ; i < optPing ; i++ )
00464     { 
00465         rc = PR_WaitSemaphore( sem1 );
00466         PR_ASSERT( PR_FAILURE != rc );
00467 
00468         (*addr)++;
00469         PR_ASSERT( (*addr % 2) == 1 );
00470         if ( optVerbose )
00471             PR_LOG( lm, msgLevel,
00472                  ( "nameshm1: Server pong: %d, i: %d", *addr, i));
00473 
00474     
00475         rc = PR_PostSemaphore( sem2 );
00476         PR_ASSERT( PR_FAILURE != rc );
00477     }
00478 
00479     rc = PR_WaitProcess( proc, &exit_status );
00480     PR_ASSERT( PR_FAILURE != rc );
00481 
00482     rc = PR_CloseSemaphore( sem1 );
00483     PR_ASSERT( PR_FAILURE != rc );
00484 
00485     rc = PR_CloseSemaphore( sem2 );
00486     PR_ASSERT( PR_FAILURE != rc );
00487 
00488     rc = PR_DeleteSemaphore( SEM_NAME1 );
00489     PR_ASSERT( PR_FAILURE != rc );
00490 
00491     rc = PR_DeleteSemaphore( SEM_NAME2 );
00492     PR_ASSERT( PR_FAILURE != rc );
00493 
00494     rc = PR_DetachSharedMemory( shm, addr );
00495     if ( PR_FAILURE == rc )
00496     {
00497         PR_LOG( lm, msgLevel,
00498             ( "nameshm1: Server: Detach: Error: %ld. OSError: %ld", 
00499                 PR_GetError(), PR_GetOSError()));
00500         failed_already = 1;
00501         return;
00502     }
00503     PR_LOG( lm, msgLevel,
00504              ( "nameshm1: Server: Detach: success: " ));
00505 
00506     rc = PR_CloseSharedMemory( shm );
00507     if ( PR_FAILURE == rc )
00508     {
00509         PR_LOG( lm, msgLevel,
00510             ( "nameshm1: Server: Close: Error: %ld. OSError: %ld", 
00511                 PR_GetError(), PR_GetOSError()));
00512         failed_already = 1;
00513         return;
00514     }
00515     PR_LOG( lm, msgLevel,
00516         ( "nameshm1: Server: Close: success: " ));
00517 
00518     rc = PR_DeleteSharedMemory( optName );
00519     if ( PR_FAILURE == rc )
00520     {
00521         PR_LOG( lm, msgLevel,
00522             ( "nameshm1: Server: Destroy: Error: %ld. OSError: %ld", 
00523                 PR_GetError(), PR_GetOSError()));
00524         failed_already = 1;
00525         return;
00526     }
00527     PR_LOG( lm, msgLevel,
00528         ( "nameshm1: Server: Destroy: success" ));
00529 
00530     return;
00531 } /* end ClientServerTest() */
00532 
00533 PRIntn main(PRIntn argc, char *argv[])
00534 {
00535     {
00536         /*
00537         ** Get command line options
00538         */
00539         PLOptStatus os;
00540         PLOptState *opt = PL_CreateOptState(argc, argv, "Cdvw:s:p:i:");
00541 
00542            while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
00543         {
00544                   if (PL_OPT_BAD == os) continue;
00545             switch (opt->option)
00546             {
00547             case 'v':  /* debug mode */
00548                 optVerbose = 1;
00549                 /* no break! fall into debug option */
00550             case 'd':  /* debug mode */
00551                 debug = 1;
00552                          msgLevel = PR_LOG_DEBUG;
00553                 break;
00554             case 'w':  /* try writing to memory mapped read-only */
00555                 optWriteRO = 1;
00556                 break;
00557             case 'C':
00558                 optClient = 1;
00559                 break;
00560             case 's':
00561                 optSize = atol(opt->value) * 1024;
00562                 break;
00563             case 'p':
00564                 optPing = atol(opt->value);
00565                 break;
00566             case 'i':
00567                 optClientIterations = atol(opt->value);
00568                 break;
00569             default:
00570                 strcpy( optName, opt->value );
00571                 break;
00572             }
00573         }
00574            PL_DestroyOptState(opt);
00575     }
00576 
00577     lm = PR_NewLogModule("Test");       /* Initialize logging */
00578     
00579     PR_LOG( lm, msgLevel,
00580              ( "nameshm1: Starting" ));
00581 
00582     if ( optClient )
00583     {
00584         DoClient();
00585     } else {
00586         BasicTest();
00587         if ( failed_already != 0 )
00588             goto Finished;
00589         ReadOnlyTest();
00590         if ( failed_already != 0 )
00591             goto Finished;
00592         ClientServerTest();
00593     }
00594 
00595 Finished:
00596     if ( debug ) printf("%s\n", (failed_already)? "FAIL" : "PASS" );
00597     return( (failed_already)? 1 : 0 );
00598 }  /* main() */
00599 /* end instrumt.c */