michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: ** File: nameshm1.c -- Test Named Shared Memory michael@0: ** michael@0: ** Description: michael@0: ** nameshm1 tests Named Shared Memory. nameshm1 performs two tests of michael@0: ** named shared memory. michael@0: ** michael@0: ** The first test is a basic test. The basic test operates as a single michael@0: ** process. The process exercises all the API elements of the facility. michael@0: ** This test also attempts to write to all locations in the shared michael@0: ** memory. michael@0: ** michael@0: ** The second test is a client-server test. The client-server test michael@0: ** creates a new instance of nameshm1, passing the -C argument to the michael@0: ** new process; this creates the client-side process. The server-side michael@0: ** (the instance of nameshm1 created from the command line) and the michael@0: ** client-side interact via inter-process semaphores to verify that the michael@0: ** shared memory segment can be read and written by both sides in a michael@0: ** synchronized maner. michael@0: ** michael@0: ** Note: Because this test runs in two processes, the log files created michael@0: ** by the test are not in chronological sequence; makes it hard to read. michael@0: ** As a temporary circumvention, I changed the definition(s) of the michael@0: ** _PUT_LOG() macro in prlog.c to force a flushall(), or equivalent. michael@0: ** This causes the log entries to be emitted in true chronological michael@0: ** order. michael@0: ** michael@0: ** Synopsis: nameshm1 [options] [name] michael@0: ** michael@0: ** Options: michael@0: ** -d Enables debug trace via PR_LOG() michael@0: ** -v Enables verbose mode debug trace via PR_LOG() michael@0: ** -w Causes the basic test to attempt to write to the segment michael@0: ** mapped as read-only. When this option is specified, the michael@0: ** test should crash with a seg-fault; this is a destructive michael@0: ** test and is considered successful when it seg-faults. michael@0: ** michael@0: ** -C Causes nameshm1 to start as the client-side of a michael@0: ** client-server pair of processes. Only the instance michael@0: ** of nameshm1 operating as the server-side process should michael@0: ** specify the -C option when creating the client-side process; michael@0: ** the -C option should not be specified at the command line. michael@0: ** The client-side uses the shared memory segment created by michael@0: ** the server-side to communicate with the server-side michael@0: ** process. michael@0: ** michael@0: ** -p Specify the number of iterations the client-server tests michael@0: ** should perform. Default: 1000. michael@0: ** michael@0: ** -s Size, in KBytes (1024), of the shared memory segment. michael@0: ** Default: (10 * 1024) michael@0: ** michael@0: ** -i Number of client-side iterations. Default: 3 michael@0: ** michael@0: ** name specifies the name of the shared memory segment to be used. michael@0: ** Default: /tmp/xxxNSPRshm michael@0: ** michael@0: ** michael@0: ** See also: prshm.h michael@0: ** michael@0: ** /lth. Aug-1999. michael@0: */ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #ifdef SYMBIAN michael@0: #define SEM_NAME1 "c:\\data\\nameshmSEM1" michael@0: #define SEM_NAME2 "c:\\data\\nameshmSEM2" michael@0: #define OPT_NAME "c:\\data\\xxxNSPRshm" michael@0: #define EXE_NAME "nspr_tests_nameshm1.exe" michael@0: #else michael@0: #define SEM_NAME1 "/tmp/nameshmSEM1" michael@0: #define SEM_NAME2 "/tmp/nameshmSEM2" michael@0: #define OPT_NAME "/tmp/xxxNSPRshm" michael@0: #define EXE_NAME "nameshm1" michael@0: #endif michael@0: #define SEM_MODE 0666 michael@0: #define SHM_MODE 0666 michael@0: michael@0: #define NameSize (1024) michael@0: michael@0: PRIntn debug = 0; michael@0: PRIntn failed_already = 0; michael@0: PRLogModuleLevel msgLevel = PR_LOG_NONE; michael@0: PRLogModuleInfo *lm; michael@0: michael@0: /* command line options */ michael@0: PRIntn optDebug = 0; michael@0: PRIntn optVerbose = 0; michael@0: PRUint32 optWriteRO = 0; /* test write to read-only memory. should crash */ michael@0: PRUint32 optClient = 0; michael@0: PRUint32 optCreate = 1; michael@0: PRUint32 optAttachRW = 1; michael@0: PRUint32 optAttachRO = 1; michael@0: PRUint32 optClose = 1; michael@0: PRUint32 optDelete = 1; michael@0: PRInt32 optPing = 1000; michael@0: PRUint32 optSize = (10 * 1024 ); michael@0: PRInt32 optClientIterations = 3; michael@0: char optName[NameSize] = OPT_NAME; michael@0: michael@0: char buf[1024] = ""; michael@0: michael@0: michael@0: static void BasicTest( void ) michael@0: { michael@0: PRSharedMemory *shm; michael@0: char *addr; /* address of shared memory segment */ michael@0: PRUint32 i; michael@0: PRInt32 rc; michael@0: michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Begin BasicTest" )); michael@0: michael@0: if ( PR_FAILURE == PR_DeleteSharedMemory( optName )) { michael@0: PR_LOG( lm, msgLevel, michael@0: ("nameshm1: Initial PR_DeleteSharedMemory() failed. No problem")); michael@0: } else michael@0: PR_LOG( lm, msgLevel, michael@0: ("nameshm1: Initial PR_DeleteSharedMemory() success")); michael@0: michael@0: michael@0: shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE ); michael@0: if ( NULL == shm ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RW Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RW Create: success: %p", shm )); michael@0: michael@0: addr = PR_AttachSharedMemory( shm , 0 ); michael@0: if ( NULL == addr ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RW Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RW Attach: success: %p", addr )); michael@0: michael@0: /* fill memory with i */ michael@0: for ( i = 0; i < optSize ; i++ ) michael@0: { michael@0: *(addr + i) = i; michael@0: } michael@0: michael@0: rc = PR_DetachSharedMemory( shm, addr ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RW Detach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RW Detach: success: " )); michael@0: michael@0: rc = PR_CloseSharedMemory( shm ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RW Close: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RW Close: success: " )); michael@0: michael@0: rc = PR_DeleteSharedMemory( optName ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RW Delete: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RW Delete: success: " )); michael@0: michael@0: PR_LOG( lm, msgLevel, michael@0: ("nameshm1: BasicTest(): Passed")); michael@0: michael@0: return; michael@0: } /* end BasicTest() */ michael@0: michael@0: static void ReadOnlyTest( void ) michael@0: { michael@0: PRSharedMemory *shm; michael@0: char *roAddr; /* read-only address of shared memory segment */ michael@0: PRInt32 rc; michael@0: michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Begin ReadOnlyTest" )); michael@0: michael@0: shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE); michael@0: if ( NULL == shm ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RO Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RO Create: success: %p", shm )); michael@0: michael@0: michael@0: roAddr = PR_AttachSharedMemory( shm , PR_SHM_READONLY ); michael@0: if ( NULL == roAddr ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RO Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RO Attach: success: %p", roAddr )); michael@0: michael@0: if ( optWriteRO ) michael@0: { michael@0: *roAddr = 0x00; /* write to read-only memory */ michael@0: failed_already = 1; michael@0: PR_LOG( lm, msgLevel, ("nameshm1: Wrote to read-only memory segment!")); michael@0: return; michael@0: } michael@0: michael@0: rc = PR_DetachSharedMemory( shm, roAddr ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RO Detach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RO Detach: success: " )); michael@0: michael@0: rc = PR_CloseSharedMemory( shm ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RO Close: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RO Close: success: " )); michael@0: michael@0: rc = PR_DeleteSharedMemory( optName ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RO Destroy: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: RO Destroy: success: " )); michael@0: michael@0: PR_LOG( lm, msgLevel, michael@0: ("nameshm1: ReadOnlyTest(): Passed")); michael@0: michael@0: return; michael@0: } /* end ReadOnlyTest() */ michael@0: michael@0: static void DoClient( void ) michael@0: { michael@0: PRStatus rc; michael@0: PRSem *sem1, *sem2; michael@0: PRSharedMemory *shm; michael@0: PRUint32 *addr; michael@0: PRInt32 i; michael@0: michael@0: PR_LOG( lm, msgLevel, michael@0: ("nameshm1: DoClient(): Starting")); michael@0: michael@0: sem1 = PR_OpenSemaphore( SEM_NAME1, 0, 0, 0 ); michael@0: PR_ASSERT( sem1 ); michael@0: michael@0: sem2 = PR_OpenSemaphore( SEM_NAME2, 0, 0, 0 ); michael@0: PR_ASSERT( sem1 ); michael@0: michael@0: shm = PR_OpenSharedMemory( optName, optSize, 0, SHM_MODE ); michael@0: if ( NULL == shm ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: DoClient(): Create: Error: %ld. OSError: %ld", michael@0: PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: DoClient(): Create: success: %p", shm )); michael@0: michael@0: addr = PR_AttachSharedMemory( shm , 0 ); michael@0: if ( NULL == addr ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: DoClient(): Attach: Error: %ld. OSError: %ld", michael@0: PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: DoClient(): Attach: success: %p", addr )); michael@0: michael@0: PR_LOG( lm, msgLevel, michael@0: ( "Client found: %s", addr)); michael@0: michael@0: PR_Sleep(PR_SecondsToInterval(4)); michael@0: for ( i = 0 ; i < optPing ; i++ ) michael@0: { michael@0: rc = PR_WaitSemaphore( sem2 ); michael@0: PR_ASSERT( PR_FAILURE != rc ); michael@0: michael@0: (*addr)++; michael@0: PR_ASSERT( (*addr % 2) == 0 ); michael@0: if ( optVerbose ) michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Client ping: %d, i: %d", *addr, i)); michael@0: michael@0: rc = PR_PostSemaphore( sem1 ); michael@0: PR_ASSERT( PR_FAILURE != rc ); michael@0: } michael@0: michael@0: rc = PR_CloseSemaphore( sem1 ); michael@0: PR_ASSERT( PR_FAILURE != rc ); michael@0: michael@0: rc = PR_CloseSemaphore( sem2 ); michael@0: PR_ASSERT( PR_FAILURE != rc ); michael@0: michael@0: rc = PR_DetachSharedMemory( shm, addr ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: DoClient(): Detach: Error: %ld. OSError: %ld", michael@0: PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: DoClient(): Detach: success: " )); michael@0: michael@0: rc = PR_CloseSharedMemory( shm ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: DoClient(): Close: Error: %ld. OSError: %ld", michael@0: PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: DoClient(): Close: success: " )); michael@0: michael@0: return; michael@0: } /* end DoClient() */ michael@0: michael@0: static void ClientServerTest( void ) michael@0: { michael@0: PRStatus rc; michael@0: PRSem *sem1, *sem2; michael@0: PRProcess *proc; michael@0: PRInt32 exit_status; michael@0: PRSharedMemory *shm; michael@0: PRUint32 *addr; michael@0: PRInt32 i; michael@0: char *child_argv[8]; michael@0: char buf[24]; michael@0: michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Begin ClientServerTest" )); michael@0: michael@0: rc = PR_DeleteSharedMemory( optName ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Destroy: failed. No problem")); michael@0: } else michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Destroy: success" )); michael@0: michael@0: michael@0: shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE); michael@0: if ( NULL == shm ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Create: success: %p", shm )); michael@0: michael@0: addr = PR_AttachSharedMemory( shm , 0 ); michael@0: if ( NULL == addr ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Attach: success: %p", addr )); michael@0: michael@0: sem1 = PR_OpenSemaphore( SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 0 ); michael@0: PR_ASSERT( sem1 ); michael@0: michael@0: sem2 = PR_OpenSemaphore( SEM_NAME2, PR_SEM_CREATE, SEM_MODE, 1 ); michael@0: PR_ASSERT( sem1 ); michael@0: michael@0: strcpy( (char*)addr, "FooBar" ); michael@0: michael@0: child_argv[0] = EXE_NAME; michael@0: child_argv[1] = "-C"; michael@0: child_argv[2] = "-p"; michael@0: sprintf( buf, "%d", optPing ); michael@0: child_argv[3] = buf; michael@0: child_argv[4] = optName; michael@0: child_argv[5] = NULL; michael@0: michael@0: proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL); michael@0: PR_ASSERT( proc ); michael@0: michael@0: PR_Sleep( PR_SecondsToInterval(4)); michael@0: michael@0: *addr = 1; michael@0: for ( i = 0 ; i < optPing ; i++ ) michael@0: { michael@0: rc = PR_WaitSemaphore( sem1 ); michael@0: PR_ASSERT( PR_FAILURE != rc ); michael@0: michael@0: (*addr)++; michael@0: PR_ASSERT( (*addr % 2) == 1 ); michael@0: if ( optVerbose ) michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server pong: %d, i: %d", *addr, i)); michael@0: michael@0: michael@0: rc = PR_PostSemaphore( sem2 ); michael@0: PR_ASSERT( PR_FAILURE != rc ); michael@0: } michael@0: michael@0: rc = PR_WaitProcess( proc, &exit_status ); michael@0: PR_ASSERT( PR_FAILURE != rc ); michael@0: michael@0: rc = PR_CloseSemaphore( sem1 ); michael@0: PR_ASSERT( PR_FAILURE != rc ); michael@0: michael@0: rc = PR_CloseSemaphore( sem2 ); michael@0: PR_ASSERT( PR_FAILURE != rc ); michael@0: michael@0: rc = PR_DeleteSemaphore( SEM_NAME1 ); michael@0: PR_ASSERT( PR_FAILURE != rc ); michael@0: michael@0: rc = PR_DeleteSemaphore( SEM_NAME2 ); michael@0: PR_ASSERT( PR_FAILURE != rc ); michael@0: michael@0: rc = PR_DetachSharedMemory( shm, addr ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Detach: Error: %ld. OSError: %ld", michael@0: PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Detach: success: " )); michael@0: michael@0: rc = PR_CloseSharedMemory( shm ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Close: Error: %ld. OSError: %ld", michael@0: PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Close: success: " )); michael@0: michael@0: rc = PR_DeleteSharedMemory( optName ); michael@0: if ( PR_FAILURE == rc ) michael@0: { michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Destroy: Error: %ld. OSError: %ld", michael@0: PR_GetError(), PR_GetOSError())); michael@0: failed_already = 1; michael@0: return; michael@0: } michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Server: Destroy: success" )); michael@0: michael@0: return; michael@0: } /* end ClientServerTest() */ michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: { michael@0: /* michael@0: ** Get command line options michael@0: */ michael@0: PLOptStatus os; michael@0: PLOptState *opt = PL_CreateOptState(argc, argv, "Cdvw:s:p:i:"); michael@0: michael@0: while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) michael@0: { michael@0: if (PL_OPT_BAD == os) continue; michael@0: switch (opt->option) michael@0: { michael@0: case 'v': /* debug mode */ michael@0: optVerbose = 1; michael@0: /* no break! fall into debug option */ michael@0: case 'd': /* debug mode */ michael@0: debug = 1; michael@0: msgLevel = PR_LOG_DEBUG; michael@0: break; michael@0: case 'w': /* try writing to memory mapped read-only */ michael@0: optWriteRO = 1; michael@0: break; michael@0: case 'C': michael@0: optClient = 1; michael@0: break; michael@0: case 's': michael@0: optSize = atol(opt->value) * 1024; michael@0: break; michael@0: case 'p': michael@0: optPing = atol(opt->value); michael@0: break; michael@0: case 'i': michael@0: optClientIterations = atol(opt->value); michael@0: break; michael@0: default: michael@0: strcpy( optName, opt->value ); michael@0: break; michael@0: } michael@0: } michael@0: PL_DestroyOptState(opt); michael@0: } michael@0: michael@0: lm = PR_NewLogModule("Test"); /* Initialize logging */ michael@0: michael@0: PR_LOG( lm, msgLevel, michael@0: ( "nameshm1: Starting" )); michael@0: michael@0: if ( optClient ) michael@0: { michael@0: DoClient(); michael@0: } else { michael@0: BasicTest(); michael@0: if ( failed_already != 0 ) michael@0: goto Finished; michael@0: ReadOnlyTest(); michael@0: if ( failed_already != 0 ) michael@0: goto Finished; michael@0: ClientServerTest(); michael@0: } michael@0: michael@0: Finished: michael@0: if ( debug ) printf("%s\n", (failed_already)? "FAIL" : "PASS" ); michael@0: return( (failed_already)? 1 : 0 ); michael@0: } /* main() */ michael@0: /* end instrumt.c */