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