diff -rdupN postgresql-9.4beta2/INSTALL postgresql-9.4beta2_qnx/INSTALL --- postgresql-9.4beta2/INSTALL 2014-07-21 15:24:46.000000000 -0400 +++ postgresql-9.4beta2_qnx/INSTALL 2014-07-29 15:40:50.000000000 -0400 @@ -1513,3 +1513,16 @@ make: *** [postgres] Error 1 your DTrace installation is too old to handle probes in static functions. You need Solaris 10u4 or newer. + __________________________________________________________________ + +QNX 6.5 and QNX 6.6 + + PostgreSQL can be built natively on QNX 6.5 SP1 using gcc. + The executables will also run on QNX 6.6. + Changes required for QNX: + a. Replace all System V shared memory with POSIX named shared memory (posix_shmem.c). + b. port.h now includes a #ifdef __QNX__ section, where macros to retry + interrupeted system calls (e.g., read, write) are defined. + This is needed because QNX does not support sigaction SA_RESTART. + + ./configure --without-readline --disable-thread-safety diff -rdupN postgresql-9.4beta2/configure postgresql-9.4beta2_qnx/configure --- postgresql-9.4beta2/configure 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/configure 2014-07-29 16:06:00.000000000 -0400 @@ -2850,7 +2850,7 @@ case $host_os in dragonfly*) template=netbsd ;; freebsd*) template=freebsd ;; hpux*) template=hpux ;; - linux*|gnu*|k*bsd*-gnu) + linux*|gnu*|k*bsd*-gnu|*qnx6*) template=linux ;; mingw*) template=win32 ;; netbsd*) template=netbsd ;; @@ -13895,16 +13895,21 @@ fi # Select shared-memory implementation type. -if test "$PORTNAME" != "win32"; then +if test "$PORTNAME" = "win32"; then -$as_echo "#define USE_SYSV_SHARED_MEMORY 1" >>confdefs.h +$as_echo "#define USE_WIN32_SHARED_MEMORY 1" >>confdefs.h - SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c" + SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c" +elif test x"$USE_POSIX_SHARED_MEMORY" = x"1" ; then + +$as_echo "#define USE_POSIX_SHARED_MEMORY 1" >>confdefs.h + + SHMEM_IMPLEMENTATION="src/backend/port/posix_shmem.c" else -$as_echo "#define USE_WIN32_SHARED_MEMORY 1" >>confdefs.h +$as_echo "#define USE_SYSV_SHARED_MEMORY 1" >>confdefs.h - SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c" + SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c" fi # Select latch implementation type. diff -rdupN postgresql-9.4beta2/configure.in postgresql-9.4beta2_qnx/configure.in --- postgresql-9.4beta2/configure.in 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/configure.in 2014-07-29 16:07:38.000000000 -0400 @@ -64,7 +64,7 @@ case $host_os in dragonfly*) template=netbsd ;; freebsd*) template=freebsd ;; hpux*) template=hpux ;; - linux*|gnu*|k*bsd*-gnu) + linux*|gnu*|k*bsd*-gnu|*qnx6*) template=linux ;; mingw*) template=win32 ;; netbsd*) template=netbsd ;; @@ -1794,12 +1794,15 @@ fi # Select shared-memory implementation type. -if test "$PORTNAME" != "win32"; then - AC_DEFINE(USE_SYSV_SHARED_MEMORY, 1, [Define to select SysV-style shared memory.]) - SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c" -else +if test "$PORTNAME" = "win32"; then AC_DEFINE(USE_WIN32_SHARED_MEMORY, 1, [Define to select Win32-style shared memory.]) SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c" +elif test x"$USE_POSIX_SHARED_MEMORY" = x"1" ; then + AC_DEFINE(USE_POSIX_SHARED_MEMORY, 1, [Define to select POSIX-style shared memory (QNX).]) + SHMEM_IMPLEMENTATION="src/backend/port/posix_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 # Select latch implementation type. diff -rdupN postgresql-9.4beta2/src/backend/Makefile postgresql-9.4beta2_qnx/src/backend/Makefile --- postgresql-9.4beta2/src/backend/Makefile 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/src/backend/Makefile 2014-07-29 15:40:51.000000000 -0400 @@ -52,6 +52,7 @@ all: submake-libpgport submake-schemapg ifneq ($(PORTNAME), cygwin) ifneq ($(PORTNAME), win32) ifneq ($(PORTNAME), aix) +ifeq (,$(findstring qnx6, $(host_os))) postgres: $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_EX) $(export_dynamic) $(call expand_subsys,$^) $(LIBS) -o $@ @@ -59,6 +60,7 @@ postgres: $(OBJS) endif endif endif +endif ifeq ($(PORTNAME), cygwin) @@ -105,6 +107,14 @@ endif endif # aix +ifneq (,$(findstring qnx6, $(host_os))) + +postgres: $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_EX) $(export_dynamic) $(call expand_subsys,$^) $(LIBS) -o $@ + ldrel -S 3M $@ + +endif # nto-qnx6.5.0 + # Update the commonly used headers before building the subdirectories $(SUBDIRS:%=%-recursive): $(top_builddir)/src/include/parser/gram.h $(top_builddir)/src/include/catalog/schemapg.h $(top_builddir)/src/include/utils/fmgroids.h $(top_builddir)/src/include/utils/errcodes.h $(top_builddir)/src/include/utils/probes.h diff -rdupN postgresql-9.4beta2/src/backend/commands/dbcommands.c postgresql-9.4beta2_qnx/src/backend/commands/dbcommands.c --- postgresql-9.4beta2/src/backend/commands/dbcommands.c 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/src/backend/commands/dbcommands.c 2014-07-29 15:40:51.000000000 -0400 @@ -348,7 +348,19 @@ createdb(const CreatedbStmt *stmt) * nor any indexes that depend on collation or ctype, so template0 can be * used as template for creating a database with any encoding or locale. */ - if (strcmp(dbtemplate, "template0") != 0) + if ((strcmp(dbtemplate, "template0") != 0) +#ifdef __QNX__ + /* KBAKER: QNX6 port has some problem here. + * Regression test fails when copying template1 to template0 with msg below: + * copying template1 to template0 FATAL: 22023: + * new LC_CTYPE (C;collate:POSIX;ctype:POSIX) is incompatible with + * the LC_CTYPE of the template database (POSIX;messages:C) + * + * For now QNX6 will live with the assumption/restriction that template1 will contain only ASCII + */ + && (strcmp(dbtemplate, "template1") != 0) +#endif + ) { if (encoding != src_encoding) ereport(ERROR, diff -rdupN postgresql-9.4beta2/src/backend/port/posix_shmem.c postgresql-9.4beta2_qnx/src/backend/port/posix_shmem.c --- postgresql-9.4beta2/src/backend/port/posix_shmem.c 1969-12-31 19:00:00.000000000 -0500 +++ postgresql-9.4beta2_qnx/src/backend/port/posix_shmem.c 2014-07-29 17:27:43.000000000 -0400 @@ -0,0 +1,492 @@ +/*------------------------------------------------------------------------- + * + * posix_shmem.c + * Implement shared memory using POSIX (non-SysV) facilities + * + * These routines represent a fairly thin layer on top of POSIX (non-SysV) shared + * memory functionality. Originally created for QNX6 port. + * + * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/port/posix_shmem.c + * + *------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_IPC_H +#include +#endif +#ifdef HAVE_SYS_SHM_H +#include +#endif + +#include "postgres.h" +#include "miscadmin.h" +#include "storage/ipc.h" +#include "storage/pg_shmem.h" + + +typedef key_t IpcMemoryKey; /* shared memory key passed to shmget(2) */ +typedef int IpcMemoryId; /* shared memory ID returned by shmget(2) */ + +#define IPCProtection (0600) /* access/modify by user only */ + +#ifdef SHM_SHARE_MMU /* use intimate shared memory on Solaris */ +#define PG_SHMAT_FLAGS SHM_SHARE_MMU +#else +#define PG_SHMAT_FLAGS 0 +#endif + +/* Linux prefers MAP_ANONYMOUS, but the flag is called MAP_ANON on other systems. */ +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +/* BSD-derived systems have MAP_HASSEMAPHORE, but it's not present (or needed) on Linux. */ +#ifndef MAP_HASSEMAPHORE +#define MAP_HASSEMAPHORE 0 +#endif + +#define PG_MMAP_FLAGS (MAP_SHARED|MAP_ANONYMOUS|MAP_HASSEMAPHORE) + +/* Some really old systems don't define MAP_FAILED. */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif + + +/* Variables to remember details for the USED named shared memory segment (small) */ +#define USED_SHMEM_SEG_NAME_MAX 100 +static char UsedShmemSegName[USED_SHMEM_SEG_NAME_MAX]; +static Size UsedShmemSegSize= 0; +unsigned long UsedShmemSegID = 0; +void *UsedShmemSegAddr = NULL; + +/* Variables to remember details for the MAIN anonymous shared memory segment (large) */ +static Size AnonymousShmemSize; +static void *AnonymousShmem; + +static void *InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size); +static void IpcMemoryDetach(int status, Datum shmaddr); +static void IpcMemoryDelete(int status, Datum shmId); +static PGShmemHeader *PGSharedMemoryAttach(IpcMemoryKey key, + IpcMemoryId *shmid); + + +static char * +keytoname(key_t key, char *name) +{ + /* POSIX shared memory segment names which start with "/" are system-wide (across processes) */ + sprintf(name, "/PgShmHdr%x", key); + return name; +} + +/* + * InternalIpcMemoryCreate(memKey, size) + * + * Attempt to create a new shared memory segment with the specified key. + * Will fail (return NULL) if such a segment already exists. If successful, + * attach the segment to the current process and return its attached address. + * On success, callbacks are registered with on_shmem_exit to detach and + * delete the segment when on_shmem_exit is called. + * + * If we fail with a failure code other than collision-with-existing-segment, + * print out an error and abort. Other types of errors are not recoverable. + */ +static void * +InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size) +{ + IpcMemoryId shmid; + void *memAddress; + + keytoname(memKey, UsedShmemSegName); + + shmid = shm_open(UsedShmemSegName, (O_CREAT | O_EXCL | O_RDWR), 0); + + if (shmid < 0) + { + int shmopen_errno = errno; + + /* + * Fail quietly if error indicates a collision with existing segment. + * One would expect EEXIST, given that we said IPC_EXCL, but perhaps + * we could get a permission violation instead? Also, EIDRM might + * occur if an old seg is slated for destruction but not gone yet. + */ + if (shmopen_errno == EEXIST || shmopen_errno == EACCES +#ifdef EIDRM + || shmopen_errno == EIDRM +#endif + ) + return NULL; + + + /* + * Else complain and abort. + */ + errno = shmopen_errno; + + ereport(FATAL, + (errmsg("could not map used shared memory (%s): %m", UsedShmemSegName), + (shmopen_errno == ENOMEM) ? + errhint("This error usually means that PostgreSQL's request " + "for a shared memory segment exceeded available memory " + "or swap space. To reduce the request size (currently " + "%lu bytes), reduce PostgreSQL's shared memory usage, " + "perhaps by reducing shared_buffers or " + "max_connections.", + (unsigned long) size) : 0)); + + return NULL; + } + + /* we need to set the size of the shared memory segment after creation */ + if (ftruncate(shmid, size) < 0) + elog(FATAL, "ftruncate(shmid=%d, size=%lu) failed: %m", shmid, (unsigned long) size); + + /* Register on-exit routine to delete the new segment */ + on_shmem_exit(IpcMemoryDelete, Int32GetDatum(shmid)); + + /* OK, should be able to attach to the segment */ + memAddress = mmap(NULL, size, (PROT_READ|PROT_WRITE), MAP_SHARED, shmid, 0); + + /* remember the USED shared memory info so we can unmap and unlink (delete) it upon exit */ + UsedShmemSegID = shmid; + UsedShmemSegAddr = memAddress; + UsedShmemSegSize = size; + + if (memAddress == (void *) -1) + //TODO: fix elog + elog(FATAL, "mmap(id=%d, name=%s, size=%lu) failed: %m", shmid, UsedShmemSegName, (unsigned long)UsedShmemSegSize); + + /* Register on-exit routine to detach new segment before deleting */ + on_shmem_exit(IpcMemoryDetach, PointerGetDatum(memAddress)); + + /* + * Store shmem key and ID in data directory lockfile. Format to try to + * keep it the same length always (trailing junk in the lockfile won't + * hurt, but might confuse humans). + */ + { + char line[64]; + + sprintf(line, "%9lu %9lu", + (unsigned long) memKey, (unsigned long) shmid); + AddToDataDirLockFile(LOCK_FILE_LINE_SHMEM_KEY, line); + } + + return memAddress; +} + +/* from process' address spaceq */ +/* (called as an on_shmem_exit callback, hence funny argument list) */ +/****************************************************************************/ +static void +IpcMemoryDetach(int status, Datum shmaddr) +{ + /* Release USED shared memory block, if any. */ + if (UsedShmemSegAddr != NULL + && munmap(UsedShmemSegAddr, UsedShmemSegSize) < 0) + elog(LOG, "munmap(%p) failed: %m", UsedShmemSegAddr); + /* Release anonymous shared memory block, if any. */ + if (AnonymousShmem != NULL + && munmap(AnonymousShmem, AnonymousShmemSize) < 0) + elog(LOG, "munmap(%p) failed: %m", AnonymousShmem); +} + +/****************************************************************************/ +/* IpcMemoryDelete(status, shmId) deletes a shared memory segment */ +/* (called as an on_shmem_exit callback, hence funny argument list) */ +/****************************************************************************/ +static void +IpcMemoryDelete(int status, Datum shmId) +{ + + if (shm_unlink(UsedShmemSegName) < 0) + elog(LOG, "shm_unlink(%s) failed: %m", + UsedShmemSegName); +} + +/* + * PGSharedMemoryIsInUse + * + * Is a previously-existing shmem segment still existing and in use? + * + * The point of this exercise is to detect the case where a prior postmaster + * crashed, but it left child backends that are still running. Therefore + * we only care about shmem segments that are associated with the intended + * DataDir. This is an important consideration since accidental matches of + * shmem segment IDs are reasonably common. + */ +bool +PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2) +{ + /* TODO: Enhance for QNX? */ + return false; +} + + +/* + * PGSharedMemoryCreate + * + * Create a shared memory segment of the given size and initialize its + * standard header. Also, register an on_shmem_exit callback to release + * the storage. + * + * Dead Postgres segments are recycled if found, but we do not fail upon + * collision with non-Postgres shmem segments. The idea here is to detect and + * re-use keys that may have been assigned by a crashed postmaster or backend. + * + * makePrivate means to always create a new segment, rather than attach to + * or recycle any existing segment. + * + * The port number is passed for possible use as a key (for SysV, we use + * it to generate the starting shmem key). In a standalone backend, + * zero will be passed. + */ +PGShmemHeader * +PGSharedMemoryCreate(Size size, bool makePrivate, int port, +/* KBAKER: added for 9.4beta */ PGShmemHeader **shim +) +{ + IpcMemoryKey NextShmemSegID; + void *memAddress; + PGShmemHeader *hdr; + struct stat statbuf; + Size sysvsize = size; + + /* Room for a header? */ + Assert(size > MAXALIGN(sizeof(PGShmemHeader))); + + /* + * As of PostgreSQL 9.3, we normally allocate only a very small amount of + * System V shared memory, and only for the purposes of providing an + * interlock to protect the data directory. The real shared memory block + * is allocated using mmap(). This works around the problem that many + * systems have very low limits on the amount of System V shared memory + * that can be allocated. Even a limit of a few megabytes will be enough + * to run many copies of PostgreSQL without needing to adjust system + * settings. + * + * However, we disable this logic in the EXEC_BACKEND case, and fall back + * to the old method of allocating the entire segment using System V + * shared memory, because there's no way to attach an mmap'd segment to a + * process after exec(). Since EXEC_BACKEND is intended only for + * developer use, this shouldn't be a big problem. + */ +#ifndef EXEC_BACKEND + { + long pagesize = sysconf(_SC_PAGE_SIZE); + + /* + * Ensure request size is a multiple of pagesize. + * + * pagesize will, for practical purposes, always be a power of two. + * But just in case it isn't, we do it this way instead of using + * TYPEALIGN(). + */ + if (pagesize > 0 && size % pagesize != 0) + size += pagesize - (size % pagesize); + + /* + * We assume that no one will attempt to run PostgreSQL 9.3 or later + * on systems that are ancient enough that anonymous shared memory is + * not supported, such as pre-2.4 versions of Linux. If that turns + * out to be false, we might need to add a run-time test here and do + * this only if the running kernel supports it. + */ + AnonymousShmem = mmap(NULL, size, PROT_READ | PROT_WRITE, PG_MMAP_FLAGS, + -1, 0); + if (AnonymousShmem == MAP_FAILED) + { + int saved_errno = errno; + + ereport(FATAL, + (errmsg("could not map anonymous shared memory: %m"), + (saved_errno == ENOMEM) ? + errhint("This error usually means that PostgreSQL's request " + "for a shared memory segment exceeded available memory " + "or swap space. To reduce the request size (currently " + "%lu bytes), reduce PostgreSQL's shared memory usage, " + "perhaps by reducing shared_buffers or " + "max_connections.", + (unsigned long) size) : 0)); + } + AnonymousShmemSize = size; + + /* Now we need only allocate a minimal-sized SysV shmem block. */ + sysvsize = sizeof(PGShmemHeader); + + + } +#endif + + /* Make sure PGSharedMemoryAttach doesn't fail without need */ + UsedShmemSegAddr = NULL; + + /* Loop till we find a free IPC key */ + NextShmemSegID = port * 1000; + + for (NextShmemSegID++;; NextShmemSegID++) + { + /* Try to create new segment */ + memAddress = InternalIpcMemoryCreate(NextShmemSegID, sysvsize); + if (memAddress) + break; /* successful create and attach */ + + /* + * Can only get here if some other process managed to create the same + * shmem key before we did. Let him have that one, loop around to try + * next key. + */ + } + + /* + * OK, we created a new segment. Mark it as created by this process. The + * order of assignments here is critical so that another Postgres process + * can't see the header as valid but belonging to an invalid PID! + */ + hdr = (PGShmemHeader *) memAddress; + hdr->creatorPID = getpid(); + hdr->magic = PGShmemMagic; + hdr->dsm_control = 0; /* KBAKER: Added for 9.4beta */ + + /* Fill in the data directory ID info, too */ + if (stat(DataDir, &statbuf) < 0) + ereport(FATAL, + (errcode_for_file_access(), + errmsg("could not stat data directory \"%s\": %m", + DataDir))); + hdr->device = statbuf.st_dev; + hdr->inode = statbuf.st_ino; + + /* + * Initialize space allocation status for segment. + */ + hdr->totalsize = size; + hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader)); + *shim = hdr; /* KBAKER: Added for 9.4beta */ + + /* Save info for possible future use */ + UsedShmemSegAddr = memAddress; + UsedShmemSegID = (unsigned long) NextShmemSegID; + + /* + * If AnonymousShmem is NULL here, then we're not using anonymous shared + * memory, and should return a pointer to the System V shared memory + * block. Otherwise, the System V shared memory block is only a shim, and + * we must return a pointer to the real block. + */ + if (AnonymousShmem == NULL) + return hdr; + memcpy(AnonymousShmem, hdr, sizeof(PGShmemHeader)); + return (PGShmemHeader *) AnonymousShmem; +} + +#ifdef EXEC_BACKEND + +/* + * PGSharedMemoryReAttach + * + * Re-attach to an already existing shared memory segment. In the non + * EXEC_BACKEND case this is not used, because postmaster children inherit + * the shared memory segment attachment via fork(). + * + * UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this + * routine. The caller must have already restored them to the postmaster's + * values. + */ +void +PGSharedMemoryReAttach(void) +{ + IpcMemoryId shmid; + void *hdr; + void *origUsedShmemSegAddr = UsedShmemSegAddr; + + Assert(UsedShmemSegAddr != NULL); + Assert(IsUnderPostmaster); + +#ifdef __CYGWIN__ + /* cygipc (currently) appears to not detach on exec. */ + PGSharedMemoryDetach(); + UsedShmemSegAddr = origUsedShmemSegAddr; +#endif + + elog(DEBUG3, "attaching to %p", UsedShmemSegAddr); + hdr = (void *) PGSharedMemoryAttach((IpcMemoryKey) UsedShmemSegID, &shmid); + if (hdr == NULL) + elog(FATAL, "could not reattach to shared memory (key=%d, addr=%p): %m", + (int) UsedShmemSegID, UsedShmemSegAddr); + if (hdr != origUsedShmemSegAddr) + elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)", + hdr, origUsedShmemSegAddr); + + UsedShmemSegAddr = hdr; /* probably redundant */ +} +#endif /* EXEC_BACKEND */ + +/* + * PGSharedMemoryDetach + * + * Detach from the shared memory segment, if still attached. This is not + * intended for use by the process that originally created the segment + * (it will have an on_shmem_exit callback registered to do that). Rather, + * this is for subprocesses that have inherited an attachment and want to + * get rid of it. + */ +void +PGSharedMemoryDetach(void) +{ + if (UsedShmemSegAddr != NULL + && munmap(UsedShmemSegAddr, UsedShmemSegSize) < 0) + { + elog(LOG, "used munmap(%p) failed: %m", UsedShmemSegAddr); + } + else + { + UsedShmemSegAddr = NULL; + } + + /* Release anonymous shared memory block, if any. */ + if (AnonymousShmem != NULL + && munmap(AnonymousShmem, AnonymousShmemSize) < 0) + elog(LOG, "anonymous munmap(%p) failed: %m", AnonymousShmem); +} + + +/* + * Attach to shared memory and make sure it has a Postgres header + * + * Returns attach address if OK, else NULL + */ +static PGShmemHeader * +PGSharedMemoryAttach(IpcMemoryKey key, IpcMemoryId *shmid) +{ + PGShmemHeader *hdr; + + keytoname(key, UsedShmemSegName); + + *shmid = shm_open(UsedShmemSegName, (O_RDWR), IPCProtection); + if (*shmid == -1) + return NULL; + + hdr = mmap(UsedShmemSegAddr, UsedShmemSegSize, (PROT_READ|PROT_WRITE), MAP_SHARED, *shmid, 0); + + if (hdr == (PGShmemHeader *) -1) + return NULL; /* failed: must be some other app's */ + + if (hdr->magic != PGShmemMagic) + { + munmap(UsedShmemSegName, UsedShmemSegSize); + return NULL; /* segment belongs to a non-Postgres app */ + } + + return hdr; +} diff -rdupN postgresql-9.4beta2/src/backend/replication/logical/logical.c postgresql-9.4beta2_qnx/src/backend/replication/logical/logical.c --- postgresql-9.4beta2/src/backend/replication/logical/logical.c 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/src/backend/replication/logical/logical.c 2014-07-29 16:16:04.000000000 -0400 @@ -168,7 +168,7 @@ StartupDecodingContext(List *output_plug ctx->out = makeStringInfo(); ctx->prepare_write = prepare_write; - ctx->write = do_write; + ctx->do_write = do_write; ctx->output_plugin_options = output_plugin_options; @@ -510,7 +510,7 @@ OutputPluginWrite(struct LogicalDecoding if (!ctx->prepared_write) elog(ERROR, "OutputPluginPrepareWrite needs to be called before OutputPluginWrite"); - ctx->write(ctx, ctx->write_location, ctx->write_xid, last_write); + ctx->do_write(ctx, ctx->write_location, ctx->write_xid, last_write); ctx->prepared_write = false; } diff -rdupN postgresql-9.4beta2/src/backend/utils/error/elog.c postgresql-9.4beta2_qnx/src/backend/utils/error/elog.c --- postgresql-9.4beta2/src/backend/utils/error/elog.c 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/src/backend/utils/error/elog.c 2014-07-29 15:40:51.000000000 -0400 @@ -3326,8 +3326,10 @@ get_errno_symbol(int errnum) return "EAGAIN"; #endif #ifdef EALREADY +#if !defined(__QNX__) case EALREADY: return "EALREADY"; +#endif /* !defined(__QNX__) */ #endif case EBADF: return "EBADF"; diff -rdupN postgresql-9.4beta2/src/backend/utils/misc/postgresql.conf.sample postgresql-9.4beta2_qnx/src/backend/utils/misc/postgresql.conf.sample --- postgresql-9.4beta2/src/backend/utils/misc/postgresql.conf.sample 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/src/backend/utils/misc/postgresql.conf.sample 2014-07-29 16:56:42.000000000 -0400 @@ -408,6 +408,7 @@ #log_disconnections = off #log_duration = off #log_error_verbosity = default # terse, default, or verbose messages +#log_error_verbosity = verbose # terse, default, or verbose messages #log_hostname = off #log_line_prefix = '' # special values: # %a = application name diff -rdupN postgresql-9.4beta2/src/include/port.h postgresql-9.4beta2_qnx/src/include/port.h --- postgresql-9.4beta2/src/include/port.h 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/src/include/port.h 2014-07-29 16:35:33.000000000 -0400 @@ -479,4 +479,97 @@ extern char *escape_single_quotes_ascii( /* port/wait_error.c */ extern char *wait_result_to_str(int exit_status); + +#if defined(__QNX__) + +#include +#include +#include + +/* QNX does not support sigaction SA_RESTART. We must retry interrupted calls (EINTR) */ + +/* Helper macros, used to build our retry macros */ +#define PG_RETRY_EINTR3(exp,val,type) ({ type _tmp_rc; do _tmp_rc = (exp); while (_tmp_rc == (val) && errno == EINTR); _tmp_rc; }) +#define PG_RETRY_EINTR(exp) PG_RETRY_EINTR3(exp,-1L,long int) +#define PG_RETRY_EINTR_FILE(exp) PG_RETRY_EINTR3(exp,NULL,FILE *) + +/* override calls known to return EINTR when interrupted */ +#define close(a) PG_RETRY_EINTR(close(a)) +#define fclose(a) PG_RETRY_EINTR(fclose(a)) +#define fdopen(a,b) PG_RETRY_EINTR_FILE(fdopen(a,b)) +#define fopen(a,b) PG_RETRY_EINTR_FILE(fopen(a,b)) +#define freopen(a,b,c) PG_RETRY_EINTR_FILE(freopen(a,b,c)) +#define fseek(a,b,c) PG_RETRY_EINTR(fseek(a,b,c)) +#define fseeko(a,b,c) PG_RETRY_EINTR(fseeko(a,b,c)) +#define ftruncate(a,b) PG_RETRY_EINTR(ftruncate(a,b)) +#define lseek(a,b,c) PG_RETRY_EINTR(lseek(a,b,c)) +#define open(a,b,...) ({ int _tmp_rc; do _tmp_rc = open(a,b,##__VA_ARGS__); while (_tmp_rc == (-1) && errno == EINTR); _tmp_rc; }) +#define shm_open(a,b,c) PG_RETRY_EINTR(shm_open(a,b,c)) +#define stat(a,b) PG_RETRY_EINTR(stat(a,b)) +#define unlink(a) PG_RETRY_EINTR(unlink(a)) + +/* reads and writes can be partial, and not always return -1 on failure. retry these partials. */ +#define read(fildes,buf,nbytes) ({ \ + ssize_t _tmp_bytes_completed = 0; \ + while (_tmp_bytes_completed < (nbytes)) { \ + ssize_t _tmp_rc = read(fildes, (char *)(buf) + _tmp_bytes_completed, (nbytes) - _tmp_bytes_completed); \ + if (_tmp_rc <= 0) { \ + if (errno == EINTR) continue; \ + if (_tmp_bytes_completed == 0) _tmp_bytes_completed = _tmp_rc; \ + break; \ + } \ + else { \ + _tmp_bytes_completed += _tmp_rc; \ + } \ + } \ + _tmp_bytes_completed; \ + }) +#define fread(buf,size,num,fp) ({ \ + size_t _tmp_elements_completed = 0; \ + while (_tmp_elements_completed < (num)) { \ + size_t _tmp_rc = fread((char *)(buf) + (_tmp_elements_completed * (size)), size, (num) - _tmp_elements_completed, fp); \ + if (_tmp_rc <= 0) { \ + if (errno == EINTR) continue; \ + if (_tmp_elements_completed == 0) _tmp_elements_completed = _tmp_rc; \ + break; \ + } \ + else { \ + _tmp_elements_completed += _tmp_rc; \ + } \ + } \ + _tmp_elements_completed; \ + }) +#define write(fildes,buf,nbytes) ({ \ + ssize_t _tmp_bytes_completed = 0; \ + while (_tmp_bytes_completed < (nbytes)) { \ + ssize_t _tmp_rc = write(fildes, (char *)(buf) + _tmp_bytes_completed, (nbytes) - _tmp_bytes_completed); \ + if (_tmp_rc <= 0) { \ + if (errno == EINTR) continue; \ + if (_tmp_bytes_completed == 0) _tmp_bytes_completed = _tmp_rc; \ + break; \ + } \ + else { \ + _tmp_bytes_completed += _tmp_rc; \ + } \ + } \ + _tmp_bytes_completed; \ + }) +#define fwrite(buf,size,num,fp) ({ \ + size_t _tmp_elements_completed = 0; \ + while (_tmp_elements_completed < (num)) { \ + size_t _tmp_rc = fwrite((char *)(buf) + (_tmp_elements_completed * (size)), size, (num) - _tmp_elements_completed, fp); \ + if (_tmp_rc <= 0) { \ + if (errno == EINTR) continue; \ + if (_tmp_elements_completed == 0) _tmp_elements_completed = _tmp_rc; \ + break; \ + } \ + else { \ + _tmp_elements_completed += _tmp_rc; \ + } \ + } \ + _tmp_elements_completed; \ + }) + +#endif /* __QNX__ */ + #endif /* PG_PORT_H */ diff -rdupN postgresql-9.4beta2/src/include/replication/logical.h postgresql-9.4beta2_qnx/src/include/replication/logical.h --- postgresql-9.4beta2/src/include/replication/logical.h 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/src/include/replication/logical.h 2014-07-29 16:15:08.000000000 -0400 @@ -49,7 +49,7 @@ typedef struct LogicalDecodingContext * User-Provided callback for writing/streaming out data. */ LogicalOutputPluginWriterPrepareWrite prepare_write; - LogicalOutputPluginWriterWrite write; + LogicalOutputPluginWriterWrite do_write; /* * Output buffer. diff -rdupN postgresql-9.4beta2/src/include/storage/dsm_impl.h postgresql-9.4beta2_qnx/src/include/storage/dsm_impl.h --- postgresql-9.4beta2/src/include/storage/dsm_impl.h 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/src/include/storage/dsm_impl.h 2014-07-29 16:27:14.000000000 -0400 @@ -32,10 +32,14 @@ #define USE_DSM_POSIX #define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_POSIX #endif + +#if !defined(__QNX__) #define USE_DSM_SYSV #ifndef DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE #define DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE DSM_IMPL_SYSV #endif +#endif /* !defined(__QNX__) */ + #define USE_DSM_MMAP #endif diff -rdupN postgresql-9.4beta2/src/template/linux postgresql-9.4beta2_qnx/src/template/linux --- postgresql-9.4beta2/src/template/linux 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/src/template/linux 2014-07-29 15:40:51.000000000 -0400 @@ -28,3 +28,10 @@ if test "$SUN_STUDIO_CC" = "yes" ; then ;; esac fi + +case $host_os in + *qnx6*) + USE_UNNAMED_POSIX_SEMAPHORES=1 + USE_POSIX_SHARED_MEMORY=1 + ;; +esac diff -rdupN postgresql-9.4beta2/src/timezone/private.h postgresql-9.4beta2_qnx/src/timezone/private.h --- postgresql-9.4beta2/src/timezone/private.h 2014-07-21 15:07:50.000000000 -0400 +++ postgresql-9.4beta2_qnx/src/timezone/private.h 2014-07-29 15:40:52.000000000 -0400 @@ -40,7 +40,10 @@ */ #ifndef remove + +#ifndef __QNX__ extern int unlink(const char *filename); +#endif #define remove unlink #endif /* !defined remove */