diff --git a/src/backend/port/Makefile b/src/backend/port/Makefile index 1370cdbb78ba941431fbdfc8dca9bae241e3d451..6979cf197392246043cf7c35a335dfce447df917 100644 --- a/src/backend/port/Makefile +++ b/src/backend/port/Makefile @@ -13,7 +13,7 @@ # be converted to Method 2. # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/port/Makefile,v 1.12 2002/05/05 00:03:28 tgl Exp $ +# $Header: /cvsroot/pgsql/src/backend/port/Makefile,v 1.13 2002/05/05 16:02:37 tgl Exp $ # #------------------------------------------------------------------------- @@ -25,7 +25,7 @@ OBJS = dynloader.o pg_sema.o pg_shmem.o OBJS += $(GETHOSTNAME) $(GETRUSAGE) $(INET_ATON) $(ISINF) $(MEMCMP) \ $(MISSING_RANDOM) $(SNPRINTF) $(SRANDOM) $(STRCASECMP) $(STRERROR) \ - $(STRTOL) $(STRTOUL) $(SNPRINTF) + $(STRTOL) $(STRTOUL) OBJS += $(TAS) @@ -68,8 +68,12 @@ darwin.dir: tas.o: tas.s $(CC) $(CFLAGS) -c $< +# IPC test program +ipc_test: ipc_test.o pg_sema.o pg_shmem.o $(MEMCMP) $(SNPRINTF) $(STRERROR) + $(CC) $(CFLAGS) $(LDFLAGS) $(export_dynamic) $^ $(LIBS) -o $@ + distclean clean: - rm -f SUBSYS.o $(OBJS) + rm -f SUBSYS.o $(OBJS) ipc_test ipc_test.o $(MAKE) -C beos clean $(MAKE) -C darwin clean $(MAKE) -C qnx4 clean diff --git a/src/backend/port/ipc_test.c b/src/backend/port/ipc_test.c new file mode 100644 index 0000000000000000000000000000000000000000..1c137ed3c42077d7b6448a2e4041f89811b1f35b --- /dev/null +++ b/src/backend/port/ipc_test.c @@ -0,0 +1,278 @@ +/*------------------------------------------------------------------------- + * + * ipc_test.c + * Simplistic testbed for shared memory and semaphore code. + * + * This file allows for quick "smoke testing" of a PG semaphore or shared + * memory implementation, with less overhead than compiling up a whole + * installation. To use: + * 1. Run configure, then edit src/include/pg_config.h to select the + * USE_xxx_SEMAPHORES and USE_xxx_SHARED_MEMORY settings you want. + * Also, adjust the pg_sema.c and pg_shmem.c symlinks in + * src/backend/port/ if needed. + * 2. In src/backend/port/, do "gmake ipc_test". + * 3. Run ipc_test and see if it works. + * 4. If it seems to work, try building the whole system and running + * the parallel regression tests for a more complete test. + * + * + * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/port/ipc_test.c,v 1.1 2002/05/05 16:02:37 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include <unistd.h> + +#include "miscadmin.h" +#include "storage/ipc.h" +#include "storage/pg_sema.h" +#include "storage/pg_shmem.h" +#include "utils/exc.h" + + +/********* stuff needed to satisfy references in shmem/sema code *********/ + + +volatile bool InterruptPending = false; +volatile bool QueryCancelPending = false; +volatile bool ProcDiePending = false; +volatile bool ImmediateInterruptOK = false; +volatile uint32 InterruptHoldoffCount = 0; +volatile uint32 CritSectionCount = 0; + +bool IsUnderPostmaster = false; + +int MaxBackends = DEF_MAXBACKENDS; +int NBuffers = DEF_NBUFFERS; + +#ifndef assert_enabled +bool assert_enabled = true; +#endif + +Exception FailedAssertion = {"Failed Assertion"}; + + +#define MAX_ON_EXITS 20 + +static struct ONEXIT +{ + void (*function) (); + Datum arg; +} on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS]; + +static int on_proc_exit_index, + on_shmem_exit_index; + +void +proc_exit(int code) +{ + shmem_exit(code); + while (--on_proc_exit_index >= 0) + (*on_proc_exit_list[on_proc_exit_index].function) (code, + on_proc_exit_list[on_proc_exit_index].arg); + exit(code); +} + +void +shmem_exit(int code) +{ + while (--on_shmem_exit_index >= 0) + (*on_shmem_exit_list[on_shmem_exit_index].function) (code, + on_shmem_exit_list[on_shmem_exit_index].arg); + on_shmem_exit_index = 0; +} + +void +on_shmem_exit(void (*function) (), Datum arg) +{ + if (on_shmem_exit_index >= MAX_ON_EXITS) + elog(FATAL, "Out of on_shmem_exit slots"); + + on_shmem_exit_list[on_shmem_exit_index].function = function; + on_shmem_exit_list[on_shmem_exit_index].arg = arg; + + ++on_shmem_exit_index; +} + +void +on_exit_reset(void) +{ + on_shmem_exit_index = 0; + on_proc_exit_index = 0; +} + +void +RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2) +{ +} + +void +ProcessInterrupts(void) +{ +} + +int +ExceptionalCondition(char *conditionName, + Exception *exceptionP, + char *detail, + char *fileName, + int lineNumber) +{ + fprintf(stderr, "TRAP: %s(\"%s:%s\", File: \"%s\", Line: %d)\n", + exceptionP->message, conditionName, + (detail == NULL ? "" : detail), + fileName, lineNumber); + abort(); + return 0; +} + +void +elog(int lev, const char *fmt,...) +{ + if (lev >= ERROR) + { + fprintf(stderr, "elog(%s)\n", fmt); + abort(); + } +} + + +/********* here's the actual test *********/ + + +typedef struct MyStorage +{ + PGShmemHeader header; + int flag; + PGSemaphoreData sem; +} MyStorage; + + +int +main(int argc, char **argv) +{ + MyStorage *storage; + int cpid; + + printf("Creating shared memory ... "); + fflush(stdout); + + storage = (MyStorage *) PGSharedMemoryCreate(8192, false, 5433); + + storage->flag = 1234; + + printf("OK\n"); + + printf("Creating semaphores ... "); + fflush(stdout); + + PGReserveSemaphores(2, 5433); + + PGSemaphoreCreate(&storage->sem); + + printf("OK\n"); + + /* sema initial value is 1, so lock should work */ + + printf("Testing Lock ... "); + fflush(stdout); + + PGSemaphoreLock(&storage->sem, false); + + printf("OK\n"); + + /* now sema value is 0, so trylock should fail */ + + printf("Testing TryLock ... "); + fflush(stdout); + + if (PGSemaphoreTryLock(&storage->sem)) + printf("unexpected result!\n"); + else + printf("OK\n"); + + /* unlocking twice and then locking twice should work... */ + + printf("Testing Multiple Lock ... "); + fflush(stdout); + + PGSemaphoreUnlock(&storage->sem); + PGSemaphoreUnlock(&storage->sem); + + PGSemaphoreLock(&storage->sem, false); + PGSemaphoreLock(&storage->sem, false); + + printf("OK\n"); + + /* check Reset too */ + + printf("Testing Reset ... "); + fflush(stdout); + + PGSemaphoreUnlock(&storage->sem); + + PGSemaphoreReset(&storage->sem); + + if (PGSemaphoreTryLock(&storage->sem)) + printf("unexpected result!\n"); + else + printf("OK\n"); + + /* Fork a child process and see if it can communicate */ + + printf("Forking child process ... "); + fflush(stdout); + + cpid = fork(); + if (cpid == 0) + { + /* In child */ + on_exit_reset(); + sleep(3); + storage->flag++; + PGSemaphoreUnlock(&storage->sem); + proc_exit(0); + } + if (cpid < 0) + { + /* Fork failed */ + printf("failed: %s\n", strerror(errno)); + proc_exit(1); + } + + printf("forked child pid %d OK\n", cpid); + + if (storage->flag != 1234) + printf("Wrong value found in shared memory!\n"); + + printf("Waiting for child (should wait 3 sec here) ... "); + fflush(stdout); + + PGSemaphoreLock(&storage->sem, false); + + printf("OK\n"); + + if (storage->flag != 1235) + printf("Wrong value found in shared memory!\n"); + + /* Test shutdown */ + + printf("Running shmem_exit processing ... "); + fflush(stdout); + + shmem_exit(0); + + printf("OK\n"); + + printf("Tests complete.\n"); + + proc_exit(0); + + return 0; /* not reached */ +}