Index: configure.in =================================================================== RCS file: /home/pqcvs/pgsql/configure.in,v retrieving revision 1.409 diff -u -u -r1.409 configure.in --- configure.in 5 May 2005 19:15:54 -0000 1.409 +++ configure.in 6 May 2005 12:03:26 -0000 @@ -1240,20 +1240,26 @@ if test x"$USE_NAMED_POSIX_SEMAPHORES" = x"1" ; then AC_DEFINE(USE_NAMED_POSIX_SEMAPHORES, 1, [Define to select named POSIX semaphores.]) SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c" +elif test x"$USE_UNNAMED_POSIX_SEMAPHORES" = x"1" ; then + AC_DEFINE(USE_UNNAMED_POSIX_SEMAPHORES, 1, [Define to select unnamed POSIX semaphores.]) + SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c" +elif test x"$USE_PIPE_SEMAPHORES" = x"1" ; then + AC_DEFINE(USE_PIPE_SEMAPHORES, 1, [Define to select pipe()-based semaphores.]) + SEMA_IMPLEMENTATION="src/backend/port/pipe_sema.c" else - if test x"$USE_UNNAMED_POSIX_SEMAPHORES" = x"1" ; then - AC_DEFINE(USE_UNNAMED_POSIX_SEMAPHORES, 1, [Define to select unnamed POSIX semaphores.]) - SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c" - else - AC_DEFINE(USE_SYSV_SEMAPHORES, 1, [Define to select SysV-style semaphores.]) - SEMA_IMPLEMENTATION="src/backend/port/sysv_sema.c" - fi + AC_DEFINE(USE_SYSV_SEMAPHORES, 1, [Define to select SysV-style semaphores.]) + SEMA_IMPLEMENTATION="src/backend/port/sysv_sema.c" fi # Select shared-memory implementation type. -AC_DEFINE(USE_SYSV_SHARED_MEMORY, 1, [Define to select SysV-style shared memory.]) -SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c" +if test x"$USE_MMAP_SHARED_MEMORY" = x"1" ; then + AC_DEFINE(USE_MMAP_SHARED_MEMORY, 1, [Define to select mmap()-based shared memory.]) + SHMEM_IMPLEMENTATION="src/backend/port/mmap_shmem.c" +else + AC_DEFINE(USE_SYSV_SHARED_MEMORY, 1, [Define to select SysV-style shared memory.]) + SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c" +fi if test "$enable_nls" = yes ; then Index: src/backend/port/mmap_shmem.c =================================================================== RCS file: src/backend/port/mmap_shmem.c diff -N src/backend/port/mmap_shmem.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/backend/port/mmap_shmem.c 6 May 2005 12:09:45 -0000 @@ -0,0 +1,138 @@ +/*------------------------------------------------------------------------- + * + * mmap_shmem.c + * Implement shared memory using mmap() + * + * Portions Copyright (c) 2005 Dag-Erling Coïdan Smørgrav + * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $PostgreSQL$ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include + +#include +#include +#include + +#include "miscadmin.h" +#include "storage/ipc.h" +#include "storage/pg_shmem.h" + +#ifdef EXEC_BACKEND +/* there is no way to reattach to a segment after exec */ +#error mmap()-based shared memory can not be combined with EXEC_BACKEND +#endif /* EXEC_BACKEND */ + +#if !defined(MAP_ANON) +#if defined(MAP_ANONYMOUS) +#define MAP_ANON MAP_ANONYMOUS +#else +static const char *DevZero = "/dev/zero"; +#endif +#endif + +static int ShmemFileDescriptor = -1; +static void *ShmemSegmentAddress = NULL; +static size_t ShmemSegmentSize = 0; + +bool +PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2) +{ + /* + * This is never the case when using mmap(), since the segments will + * vanish into thin air when postmaster exits or crashes. + */ + return false; +} + +static void +PGSharedMemoryDestroy(int code, Datum arg) +{ + PGSharedMemoryDetach(); +} + +PGShmemHeader * +PGSharedMemoryCreate(uint32 size, bool makePrivate, int port) +{ + PGShmemHeader *hdr; + void *memAddress; + int fd, flags, prot; + + /* Room for a header? */ + Assert(size > MAXALIGN(sizeof(PGShmemHeader))); + + /* flags: shared, keep out of core dump, don't sync gratuitously */ + flags = MAP_SHARED; +#ifdef MAP_NOCORE + flags |= MAP_NOCORE; +#endif +#ifdef MAP_NOSYNC + flags |= MAP_NOSYNC; +#endif + + /* file descriptor */ +#if defined(MAP_ANON) + /* no file needed, just set MAP_ANON */ + fd = -1; + flags |= MAP_ANON; +#else + /* use /dev/zero; need a new file descriptor for every segment */ + if ((fd = open(DevZero, O_RDWR)) == -1) + ereport(FATAL, + (errmsg("could not create shared memory segment: %m"), + errdetail("Failed system call was open(path='%s', flags=0%o).", + DevZero, O_RDWR))); +#endif + + /* protection: read-write */ + prot = PROT_READ | PROT_WRITE; + + /* map it */ + memAddress = mmap(NULL, (size_t) size, prot, flags, fd, 0); + if (memAddress == NULL) + ereport(FATAL, + (errmsg("could not create shared memory segment: %m"), + errdetail("Failed system call was mmap(size=%lu, prot=0%o, flags=0%o, fd=%d).", + (unsigned long) size, prot, flags, fd))); + + /* + * Most header fields are irrelevant since no-one will ever see this + * segment except us and our children. We only need to fill in those + * required for memory management. + */ + hdr = (PGShmemHeader *) memAddress; + hdr->totalsize = size; + hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader)); + + /* save these for detach */ + ShmemFileDescriptor = fd; + ShmemSegmentAddress = memAddress; + ShmemSegmentSize = (size_t) size; + + on_shmem_exit(PGSharedMemoryDestroy, 0); + + return hdr; +} + +void +PGSharedMemoryDetach(void) +{ + if (ShmemSegmentAddress != NULL) { + if (munmap(ShmemSegmentAddress, ShmemSegmentSize) == -1) + ereport(WARNING, + (errmsg("could not detach from shared memory segment: %m"), + errdetail("Failed system call was munmap(addr=%p, len=%lu).", + ShmemSegmentAddress, (unsigned long) ShmemSegmentSize))); + if (ShmemFileDescriptor != -1) + close(ShmemFileDescriptor); /* XXX may fail, not important */ + ShmemSegmentAddress = NULL; + ShmemSegmentSize = 0; + ShmemFileDescriptor = -1; + } +} Index: src/backend/port/pipe_sema.c =================================================================== RCS file: src/backend/port/pipe_sema.c diff -N src/backend/port/pipe_sema.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/backend/port/pipe_sema.c 4 May 2005 13:07:11 -0000 @@ -0,0 +1,303 @@ +/*------------------------------------------------------------------------- + * + * pipe_sema.c + * Implement PGSemaphores using pipes + * + * + * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $PostgreSQL$ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include +#include +#include +#include + +#include "miscadmin.h" +#include "storage/ipc.h" +#include "storage/pg_sema.h" + +static const char SemaphoreData = 'U'; +static PGSemaphore SemaphoreListHead; + +static void +PGSemaphoreDestroy(int code, Datum arg) +{ + while (SemaphoreListHead != NULL) { + close(SemaphoreListHead->semPipe[0]); + close(SemaphoreListHead->semPipe[1]); + SemaphoreListHead->semPipe[0] = SemaphoreListHead->semPipe[1] = -1; + SemaphoreListHead = SemaphoreListHead->next; + } +} + +/* + * Module initialization (called during postmaster start or shmem reinit) + */ +void +PGReserveSemaphores(int maxSemas, int port) +{ + ereport(DEBUG4, + (errmsg("initializing semaphores"))); + on_shmem_exit(PGSemaphoreDestroy, 0); +} + +/* + * Initialize a PGSemaphore structure to represent a sema with count 1 + */ +void +PGSemaphoreCreate(PGSemaphore sema) +{ + /* open the pipe */ + if (pipe(sema->semPipe) != 0) + ereport(FATAL, + (errmsg("could not create semaphore: %m"), + errdetail("Failed system call was pipe()."))); + /* set the read side non-blocking so we can implement TryLock */ + /* + * We could leave this out and set O_NONBLOCK only when we need it, + * i.e. in PGSemaphoreTryLock(), but I'm unsure about the consequences + * if two processes share a semaphore and one sets it non-blocking; is + * the flag set for both processes? For now, assume the read side is + * always non-blocking, until I have time to check SUSv3. + */ + if (fcntl(sema->semPipe[0], F_SETFL, O_NONBLOCK) != 0) + ereport(FATAL, + (errmsg("could not create semaphore: %m"), + errdetail("Failed system call was fcntl(fildes=%d, cmd=0%o, arg=0%o).", + sema->semPipe[0], F_SETFL, O_NONBLOCK))); + ereport(DEBUG4, + (errmsg("semaphore created: r%dw%d", + sema->semPipe[0], sema->semPipe[1]))); + + /* keep track */ + sema->next = SemaphoreListHead; + SemaphoreListHead = sema; + + /* bump */ + PGSemaphoreUnlock(sema); +} + +/* + * Reset a previously-initialized PGSemaphore to have count 0 + */ +void +PGSemaphoreReset(PGSemaphore sema) +{ + ssize_t rlen; + char data; + + Assert(SemaphoreListHead != NULL && + sema->semPipe[0] >= 0 && sema->semPipe[1] >= 0 && + sema->semPipe[0] != sema->semPipe[1]); + ereport(DEBUG4, + (errmsg("resetting semaphore r%dw%d", + sema->semPipe[0], sema->semPipe[1]))); + for (;;) { + rlen = read(sema->semPipe[0], &data, 1); + switch (rlen) { + case 1: + /* go on */ + Assert(data == SemaphoreData); + break; + case 0: + /* done */ + ereport(DEBUG4, + (errmsg("reset semaphore r%dw%d", + sema->semPipe[0], sema->semPipe[1]))); + return; + case -1: + switch (errno) { +#ifdef EAGAIN + case EAGAIN: +#endif +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: +#endif + /* done */ + ereport(DEBUG4, + (errmsg("reset semaphore r%dw%d", + sema->semPipe[0], sema->semPipe[1]))); + return; + case EINTR: + /* try again */ + break; + default: + /* oops! */ + ereport(FATAL, + (errmsg("could not reset semaphore: %m"), + errdetail("Failed system call was read(fildes=%d, buf=%p, nbyte=%d).", + sema->semPipe[0], &data, 1))); + break; + } + break; + default: + ereport(PANIC, + (errmsg("read on semaphore returned %ld", (long)rlen))); + } + } +} + +/* + * Lock a semaphore (decrement count), blocking if count would be < 0 + */ +void +PGSemaphoreLock(PGSemaphore sema, bool interruptOK) +{ + fd_set fds, rfds; + ssize_t rlen; + char data; + + Assert(SemaphoreListHead != NULL && + sema->semPipe[0] >= 0 && sema->semPipe[1] >= 0 && + sema->semPipe[0] != sema->semPipe[1]); + ereport(DEBUG4, + (errmsg("locking semaphore r%dw%d", + sema->semPipe[0], sema->semPipe[1]))); + FD_ZERO(&fds); + FD_SET(sema->semPipe[0], &fds); + for (;;) { + /* + * See the corresponding function in sysv_sema.c for a detailed + * explanation of the interrupt handling. + */ + ImmediateInterruptOK = interruptOK; + CHECK_FOR_INTERRUPTS(); + rlen = read(sema->semPipe[0], &data, 1); + ImmediateInterruptOK = false; + switch (rlen) { + case 1: + Assert(data == SemaphoreData); + ereport(DEBUG4, + (errmsg("locked semaphore r%dw%d", + sema->semPipe[0], sema->semPipe[1]))); + return; + case -1: + switch (errno) { +#ifdef EAGAIN + case EAGAIN: +#endif +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: +#endif + /* wait, and try again */ + rfds = fds; + select(sema->semPipe[0] + 1, &rfds, NULL, NULL, NULL); + break; + case EINTR: + /* try again */ + break; + default: + /* oops! */ + ereport(FATAL, + (errmsg("could not decrement semaphore: %m"), + errdetail("Failed system call was read(fildes=%d, buf=%p, nbyte=%d).", + sema->semPipe[0], &data, 1))); + break; + } + break; + default: + ereport(PANIC, + (errmsg("short read on semaphore"))); + } + } +} + +/* + * Unlock a semaphore (increment count) + */ +void +PGSemaphoreUnlock(PGSemaphore sema) +{ + void (*osig)(int); + ssize_t wlen; + + Assert(SemaphoreListHead != NULL && + sema->semPipe[0] >= 0 && sema->semPipe[1] >= 0 && + sema->semPipe[0] != sema->semPipe[1]); + ereport(DEBUG4, + (errmsg("unlocking semaphore r%dw%d", + sema->semPipe[0], sema->semPipe[1]))); + osig = signal(SIGPIPE, SIG_IGN); + wlen = write(sema->semPipe[1], &SemaphoreData, 1); + signal(SIGPIPE, osig); + switch (wlen) { + case 1: + /* done */ + ereport(DEBUG4, + (errmsg("unlocked semaphore r%dw%d", + sema->semPipe[0], sema->semPipe[1]))); + return; + case -1: + /* failed */ + ereport(FATAL, + (errmsg("could not increment semaphore: %m"), + errdetail("Failed system call was write(fildes=%d, buf=%p, nbyte=%d).", + sema->semPipe[1], &SemaphoreData, 1))); + default: + ereport(PANIC, + (errmsg("short write on semaphore"))); + } +} + +/* + * Lock a semaphore only if able to do so without blocking + */ +bool +PGSemaphoreTryLock(PGSemaphore sema) +{ + ssize_t rlen; + char data; + + Assert(SemaphoreListHead != NULL && + sema->semPipe[0] >= 0 && sema->semPipe[1] >= 0 && + sema->semPipe[0] != sema->semPipe[1]); + ereport(DEBUG4, + (errmsg("trying to lock semaphore r%dw%d", + sema->semPipe[0], sema->semPipe[1]))); + for (;;) { + rlen = read(sema->semPipe[0], &data, 1); + switch (rlen) { + case 1: + Assert(data == SemaphoreData); + ereport(DEBUG4, + (errmsg("locked semaphore r%dw%d", + sema->semPipe[0], sema->semPipe[1]))); + return true; + case -1: + switch (errno) { +#ifdef EAGAIN + case EAGAIN: +#endif +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: +#endif + /* failed */ + ereport(DEBUG4, + (errmsg("failed to lock semaphore r%dw%d", + sema->semPipe[0], sema->semPipe[1]))); + return false; + case EINTR: + /* try again */ + break; + default: + /* oops! */ + ereport(FATAL, + (errmsg("could not decrement semaphore: %m"), + errdetail("Failed system call was read(fildes=%d, buf=%p, nbyte=%d).", + sema->semPipe[0], &data, 1))); + break; + } + break; + default: + ereport(PANIC, + (errmsg("short read on semaphore"))); + } + } +} Index: src/include/pg_config.h.in =================================================================== RCS file: /home/pqcvs/pgsql/src/include/pg_config.h.in,v retrieving revision 1.82 diff -u -u -r1.82 pg_config.h.in --- src/include/pg_config.h.in 11 Mar 2005 17:20:34 -0000 1.82 +++ src/include/pg_config.h.in 4 May 2005 11:40:52 -0000 @@ -639,12 +639,18 @@ (--enable-integer-datetimes) */ #undef USE_INTEGER_DATETIMES +/* Define to 1 to select mmap()-based shared memory */ +#undef USE_MMAP_SHARED_MEMORY + /* Define to select named POSIX semaphores. */ #undef USE_NAMED_POSIX_SEMAPHORES /* Define to 1 to build with PAM support. (--with-pam) */ #undef USE_PAM +/* Define to 1 to select pipe()-based semaphores */ +#undef USE_PIPE_SEMAPHORES + /* Define to 1 to build with Rendezvous support. (--with-rendezvous) */ #undef USE_RENDEZVOUS Index: src/include/storage/pg_sema.h =================================================================== RCS file: /home/pqcvs/pgsql/src/include/storage/pg_sema.h,v retrieving revision 1.7 diff -u -u -r1.7 pg_sema.h --- src/include/storage/pg_sema.h 31 Dec 2004 22:03:42 -0000 1.7 +++ src/include/storage/pg_sema.h 4 May 2005 12:48:19 -0000 @@ -54,6 +54,14 @@ } PGSemaphoreData; #endif +#ifdef USE_PIPE_SEMAPHORES +typedef struct PGSemaphoreData +{ + int semPipe[2]; /* pipe descriptor set */ + struct PGSemaphoreData *next; +} PGSemaphoreData; +#endif + typedef PGSemaphoreData *PGSemaphore; Index: src/template/freebsd =================================================================== RCS file: /home/pqcvs/pgsql/src/template/freebsd,v retrieving revision 1.34 diff -u -u -r1.34 freebsd --- src/template/freebsd 2 Dec 2004 18:11:40 -0000 1.34 +++ src/template/freebsd 4 May 2005 11:32:16 -0000 @@ -1,3 +1,6 @@ case $host_cpu in alpha*) CFLAGS="-O";; # alpha has problems with -O2 esac + +USE_PIPE_SEMAPHORES=1 +USE_MMAP_SHARED_MEMORY=1 Index: src/template/linux =================================================================== RCS file: /home/pqcvs/pgsql/src/template/linux,v retrieving revision 1.27 diff -u -u -r1.27 linux --- src/template/linux 2 Dec 2004 18:11:40 -0000 1.27 +++ src/template/linux 4 May 2005 11:32:30 -0000 @@ -1,2 +1,5 @@ # Force _GNU_SOURCE on; plperl is broken with Perl 5.8.0 otherwise CPPFLAGS="-D_GNU_SOURCE" + +USE_PIPE_SEMAPHORES=1 +USE_MMAP_SHARED_MEMORY=1