mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-30 00:31:32 +02:00
1a321f26d8
about a third, make it work on non-Windows platforms again. (But perhaps I broke the WIN32 code, since I have no way to test that.) Fold all the paths that fork postmaster child processes to go through the single routine SubPostmasterMain, which takes care of resurrecting the state that would normally be inherited from the postmaster (including GUC variables). Clean up some places where there's no particularly good reason for the EXEC and non-EXEC cases to work differently. Take care of one or two FIXMEs that remained in the code.
321 lines
6.2 KiB
C
321 lines
6.2 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* 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-2003, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* $PostgreSQL: pgsql/src/backend/port/ipc_test.c,v 1.13 2004/05/28 05:12:55 tgl Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
#include "miscadmin.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/pg_sema.h"
|
|
#include "storage/pg_shmem.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 = 32;
|
|
int NBuffers = 64;
|
|
|
|
#ifndef assert_enabled
|
|
bool assert_enabled = true;
|
|
#endif
|
|
|
|
|
|
#define MAX_ON_EXITS 20
|
|
|
|
static struct ONEXIT
|
|
{
|
|
void (*function) (int code, Datum arg);
|
|
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) (int code, Datum arg), 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,
|
|
char *errorType,
|
|
char *fileName,
|
|
int lineNumber)
|
|
{
|
|
fprintf(stderr, "TRAP: %s(\"%s\", File: \"%s\", Line: %d)\n",
|
|
errorType, conditionName,
|
|
fileName, lineNumber);
|
|
abort();
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
errstart(int elevel, const char *filename, int lineno,
|
|
const char *funcname)
|
|
{
|
|
return (elevel >= ERROR);
|
|
}
|
|
|
|
void
|
|
errfinish(int dummy,...)
|
|
{
|
|
proc_exit(1);
|
|
}
|
|
|
|
void
|
|
elog_finish(int elevel, const char *fmt,...)
|
|
{
|
|
fprintf(stderr, "ERROR: %s\n", fmt);
|
|
proc_exit(1);
|
|
}
|
|
|
|
int
|
|
errcode(int sqlerrcode)
|
|
{
|
|
return 0; /* return value does not matter */
|
|
}
|
|
|
|
int
|
|
errmsg(const char *fmt,...)
|
|
{
|
|
fprintf(stderr, "ERROR: %s\n", fmt);
|
|
return 0; /* return value does not matter */
|
|
}
|
|
|
|
int
|
|
errmsg_internal(const char *fmt,...)
|
|
{
|
|
fprintf(stderr, "ERROR: %s\n", fmt);
|
|
return 0; /* return value does not matter */
|
|
}
|
|
|
|
int
|
|
errdetail(const char *fmt,...)
|
|
{
|
|
fprintf(stderr, "DETAIL: %s\n", fmt);
|
|
return 0; /* return value does not matter */
|
|
}
|
|
|
|
int
|
|
errhint(const char *fmt,...)
|
|
{
|
|
fprintf(stderr, "HINT: %s\n", fmt);
|
|
return 0; /* return value does not matter */
|
|
}
|
|
|
|
|
|
/********* 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 */
|
|
}
|