diff --git a/configure b/configure index a45be67d503..c10d9549a40 100755 --- a/configure +++ b/configure @@ -14786,13 +14786,6 @@ $as_echo "#define USE_WIN32_SHARED_MEMORY 1" >>confdefs.h SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c" fi -# Select latch implementation type. -if test "$PORTNAME" != "win32"; then - LATCH_IMPLEMENTATION="src/backend/port/unix_latch.c" -else - LATCH_IMPLEMENTATION="src/backend/port/win32_latch.c" -fi - # If not set in template file, set bytes to use libc memset() if test x"$MEMSET_LOOP_LIMIT" = x"" ; then MEMSET_LOOP_LIMIT=1024 @@ -15868,7 +15861,7 @@ fi ac_config_files="$ac_config_files GNUmakefile src/Makefile.global" -ac_config_links="$ac_config_links src/backend/port/dynloader.c:src/backend/port/dynloader/${template}.c src/backend/port/pg_sema.c:${SEMA_IMPLEMENTATION} src/backend/port/pg_shmem.c:${SHMEM_IMPLEMENTATION} src/backend/port/pg_latch.c:${LATCH_IMPLEMENTATION} src/include/dynloader.h:src/backend/port/dynloader/${template}.h src/include/pg_config_os.h:src/include/port/${template}.h src/Makefile.port:src/makefiles/Makefile.${template}" +ac_config_links="$ac_config_links src/backend/port/dynloader.c:src/backend/port/dynloader/${template}.c src/backend/port/pg_sema.c:${SEMA_IMPLEMENTATION} src/backend/port/pg_shmem.c:${SHMEM_IMPLEMENTATION} src/include/dynloader.h:src/backend/port/dynloader/${template}.h src/include/pg_config_os.h:src/include/port/${template}.h src/Makefile.port:src/makefiles/Makefile.${template}" if test "$PORTNAME" = "win32"; then @@ -16592,7 +16585,6 @@ do "src/backend/port/dynloader.c") CONFIG_LINKS="$CONFIG_LINKS src/backend/port/dynloader.c:src/backend/port/dynloader/${template}.c" ;; "src/backend/port/pg_sema.c") CONFIG_LINKS="$CONFIG_LINKS src/backend/port/pg_sema.c:${SEMA_IMPLEMENTATION}" ;; "src/backend/port/pg_shmem.c") CONFIG_LINKS="$CONFIG_LINKS src/backend/port/pg_shmem.c:${SHMEM_IMPLEMENTATION}" ;; - "src/backend/port/pg_latch.c") CONFIG_LINKS="$CONFIG_LINKS src/backend/port/pg_latch.c:${LATCH_IMPLEMENTATION}" ;; "src/include/dynloader.h") CONFIG_LINKS="$CONFIG_LINKS src/include/dynloader.h:src/backend/port/dynloader/${template}.h" ;; "src/include/pg_config_os.h") CONFIG_LINKS="$CONFIG_LINKS src/include/pg_config_os.h:src/include/port/${template}.h" ;; "src/Makefile.port") CONFIG_LINKS="$CONFIG_LINKS src/Makefile.port:src/makefiles/Makefile.${template}" ;; diff --git a/configure.in b/configure.in index c298926b667..47d0f584ded 100644 --- a/configure.in +++ b/configure.in @@ -1976,13 +1976,6 @@ else SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c" fi -# Select latch implementation type. -if test "$PORTNAME" != "win32"; then - LATCH_IMPLEMENTATION="src/backend/port/unix_latch.c" -else - LATCH_IMPLEMENTATION="src/backend/port/win32_latch.c" -fi - # If not set in template file, set bytes to use libc memset() if test x"$MEMSET_LOOP_LIMIT" = x"" ; then MEMSET_LOOP_LIMIT=1024 @@ -2178,7 +2171,6 @@ AC_CONFIG_LINKS([ src/backend/port/dynloader.c:src/backend/port/dynloader/${template}.c src/backend/port/pg_sema.c:${SEMA_IMPLEMENTATION} src/backend/port/pg_shmem.c:${SHMEM_IMPLEMENTATION} - src/backend/port/pg_latch.c:${LATCH_IMPLEMENTATION} src/include/dynloader.h:src/backend/port/dynloader/${template}.h src/include/pg_config_os.h:src/include/port/${template}.h src/Makefile.port:src/makefiles/Makefile.${template} diff --git a/src/backend/Makefile b/src/backend/Makefile index b3d5e2e1bd9..d22dbbf53b6 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -306,8 +306,7 @@ ifeq ($(PORTNAME), win32) endif distclean: clean - rm -f port/tas.s port/dynloader.c port/pg_sema.c port/pg_shmem.c \ - port/pg_latch.c + rm -f port/tas.s port/dynloader.c port/pg_sema.c port/pg_shmem.c maintainer-clean: distclean rm -f bootstrap/bootparse.c \ diff --git a/src/backend/port/.gitignore b/src/backend/port/.gitignore index 7d3ac4ab427..9f4f1af5e93 100644 --- a/src/backend/port/.gitignore +++ b/src/backend/port/.gitignore @@ -1,5 +1,4 @@ /dynloader.c -/pg_latch.c /pg_sema.c /pg_shmem.c /tas.s diff --git a/src/backend/port/Makefile b/src/backend/port/Makefile index c6b1d20c55e..89549d0d2b7 100644 --- a/src/backend/port/Makefile +++ b/src/backend/port/Makefile @@ -21,7 +21,7 @@ subdir = src/backend/port top_builddir = ../../.. include $(top_builddir)/src/Makefile.global -OBJS = atomics.o dynloader.o pg_sema.o pg_shmem.o pg_latch.o $(TAS) +OBJS = atomics.o dynloader.o pg_sema.o pg_shmem.o $(TAS) ifeq ($(PORTNAME), darwin) SUBDIRS += darwin diff --git a/src/backend/port/win32_latch.c b/src/backend/port/win32_latch.c deleted file mode 100644 index bbf1b24bdf3..00000000000 --- a/src/backend/port/win32_latch.c +++ /dev/null @@ -1,349 +0,0 @@ -/*------------------------------------------------------------------------- - * - * win32_latch.c - * Routines for inter-process latches - * - * See unix_latch.c for header comments for the exported functions; - * the API presented here is supposed to be the same as there. - * - * The Windows implementation uses Windows events that are inherited by - * all postmaster child processes. - * - * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * IDENTIFICATION - * src/backend/port/win32_latch.c - * - *------------------------------------------------------------------------- - */ -#include "postgres.h" - -#include -#include -#include -#include - -#include "miscadmin.h" -#include "portability/instr_time.h" -#include "postmaster/postmaster.h" -#include "storage/barrier.h" -#include "storage/latch.h" -#include "storage/pmsignal.h" -#include "storage/shmem.h" - - -void -InitializeLatchSupport(void) -{ - /* currently, nothing to do here for Windows */ -} - -void -InitLatch(volatile Latch *latch) -{ - latch->is_set = false; - latch->owner_pid = MyProcPid; - latch->is_shared = false; - - latch->event = CreateEvent(NULL, TRUE, FALSE, NULL); - if (latch->event == NULL) - elog(ERROR, "CreateEvent failed: error code %lu", GetLastError()); -} - -void -InitSharedLatch(volatile Latch *latch) -{ - SECURITY_ATTRIBUTES sa; - - latch->is_set = false; - latch->owner_pid = 0; - latch->is_shared = true; - - /* - * Set up security attributes to specify that the events are inherited. - */ - ZeroMemory(&sa, sizeof(sa)); - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - - latch->event = CreateEvent(&sa, TRUE, FALSE, NULL); - if (latch->event == NULL) - elog(ERROR, "CreateEvent failed: error code %lu", GetLastError()); -} - -void -OwnLatch(volatile Latch *latch) -{ - /* Sanity checks */ - Assert(latch->is_shared); - if (latch->owner_pid != 0) - elog(ERROR, "latch already owned"); - - latch->owner_pid = MyProcPid; -} - -void -DisownLatch(volatile Latch *latch) -{ - Assert(latch->is_shared); - Assert(latch->owner_pid == MyProcPid); - - latch->owner_pid = 0; -} - -int -WaitLatch(volatile Latch *latch, int wakeEvents, long timeout) -{ - return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout); -} - -int -WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, - long timeout) -{ - DWORD rc; - instr_time start_time, - cur_time; - long cur_timeout; - HANDLE events[4]; - HANDLE latchevent; - HANDLE sockevent = WSA_INVALID_EVENT; - int numevents; - int result = 0; - int pmdeath_eventno = 0; - - Assert(wakeEvents != 0); /* must have at least one wake event */ - - /* waiting for socket readiness without a socket indicates a bug */ - if (sock == PGINVALID_SOCKET && - (wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) != 0) - elog(ERROR, "cannot wait on socket event without a socket"); - - if ((wakeEvents & WL_LATCH_SET) && latch->owner_pid != MyProcPid) - elog(ERROR, "cannot wait on a latch owned by another process"); - - /* - * Initialize timeout if requested. We must record the current time so - * that we can determine the remaining timeout if WaitForMultipleObjects - * is interrupted. - */ - if (wakeEvents & WL_TIMEOUT) - { - INSTR_TIME_SET_CURRENT(start_time); - Assert(timeout >= 0 && timeout <= INT_MAX); - cur_timeout = timeout; - } - else - cur_timeout = INFINITE; - - /* - * Construct an array of event handles for WaitforMultipleObjects(). - * - * Note: pgwin32_signal_event should be first to ensure that it will be - * reported when multiple events are set. We want to guarantee that - * pending signals are serviced. - */ - latchevent = latch->event; - - events[0] = pgwin32_signal_event; - events[1] = latchevent; - numevents = 2; - if (wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) - { - /* Need an event object to represent events on the socket */ - int flags = FD_CLOSE; /* always check for errors/EOF */ - - if (wakeEvents & WL_SOCKET_READABLE) - flags |= FD_READ; - if (wakeEvents & WL_SOCKET_WRITEABLE) - flags |= FD_WRITE; - - sockevent = WSACreateEvent(); - if (sockevent == WSA_INVALID_EVENT) - elog(ERROR, "failed to create event for socket: error code %u", - WSAGetLastError()); - if (WSAEventSelect(sock, sockevent, flags) != 0) - elog(ERROR, "failed to set up event for socket: error code %u", - WSAGetLastError()); - - events[numevents++] = sockevent; - } - if (wakeEvents & WL_POSTMASTER_DEATH) - { - pmdeath_eventno = numevents; - events[numevents++] = PostmasterHandle; - } - - /* Ensure that signals are serviced even if latch is already set */ - pgwin32_dispatch_queued_signals(); - - do - { - /* - * The comment in unix_latch.c's equivalent to this applies here as - * well. At least after mentally replacing self-pipe with windows - * event. There's no danger of overflowing, as "Setting an event that - * is already set has no effect.". - */ - if ((wakeEvents & WL_LATCH_SET) && latch->is_set) - { - result |= WL_LATCH_SET; - - /* - * Leave loop immediately, avoid blocking again. We don't attempt - * to report any other events that might also be satisfied. - */ - break; - } - - rc = WaitForMultipleObjects(numevents, events, FALSE, cur_timeout); - - if (rc == WAIT_FAILED) - elog(ERROR, "WaitForMultipleObjects() failed: error code %lu", - GetLastError()); - else if (rc == WAIT_TIMEOUT) - { - result |= WL_TIMEOUT; - } - else if (rc == WAIT_OBJECT_0) - { - /* Service newly-arrived signals */ - pgwin32_dispatch_queued_signals(); - } - else if (rc == WAIT_OBJECT_0 + 1) - { - /* - * Reset the event. We'll re-check the, potentially, set latch on - * next iteration of loop, but let's not waste the cycles to - * update cur_timeout below. - */ - if (!ResetEvent(latchevent)) - elog(ERROR, "ResetEvent failed: error code %lu", GetLastError()); - - continue; - } - else if ((wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) && - rc == WAIT_OBJECT_0 + 2) /* socket is at event slot 2 */ - { - WSANETWORKEVENTS resEvents; - - ZeroMemory(&resEvents, sizeof(resEvents)); - if (WSAEnumNetworkEvents(sock, sockevent, &resEvents) != 0) - elog(ERROR, "failed to enumerate network events: error code %u", - WSAGetLastError()); - if ((wakeEvents & WL_SOCKET_READABLE) && - (resEvents.lNetworkEvents & FD_READ)) - { - result |= WL_SOCKET_READABLE; - } - if ((wakeEvents & WL_SOCKET_WRITEABLE) && - (resEvents.lNetworkEvents & FD_WRITE)) - { - result |= WL_SOCKET_WRITEABLE; - } - if (resEvents.lNetworkEvents & FD_CLOSE) - { - if (wakeEvents & WL_SOCKET_READABLE) - result |= WL_SOCKET_READABLE; - if (wakeEvents & WL_SOCKET_WRITEABLE) - result |= WL_SOCKET_WRITEABLE; - } - } - else if ((wakeEvents & WL_POSTMASTER_DEATH) && - rc == WAIT_OBJECT_0 + pmdeath_eventno) - { - /* - * Postmaster apparently died. Since the consequences of falsely - * returning WL_POSTMASTER_DEATH could be pretty unpleasant, we - * take the trouble to positively verify this with - * PostmasterIsAlive(), even though there is no known reason to - * think that the event could be falsely set on Windows. - */ - if (!PostmasterIsAlive()) - result |= WL_POSTMASTER_DEATH; - } - else - elog(ERROR, "unexpected return code from WaitForMultipleObjects(): %lu", rc); - - /* If we're not done, update cur_timeout for next iteration */ - if (result == 0 && (wakeEvents & WL_TIMEOUT)) - { - INSTR_TIME_SET_CURRENT(cur_time); - INSTR_TIME_SUBTRACT(cur_time, start_time); - cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time); - if (cur_timeout <= 0) - { - /* Timeout has expired, no need to continue looping */ - result |= WL_TIMEOUT; - } - } - } while (result == 0); - - /* Clean up the event object we created for the socket */ - if (sockevent != WSA_INVALID_EVENT) - { - WSAEventSelect(sock, NULL, 0); - WSACloseEvent(sockevent); - } - - return result; -} - -/* - * The comments above the unix implementation (unix_latch.c) of this function - * apply here as well. - */ -void -SetLatch(volatile Latch *latch) -{ - HANDLE handle; - - /* - * The memory barrier has be to be placed here to ensure that any flag - * variables possibly changed by this process have been flushed to main - * memory, before we check/set is_set. - */ - pg_memory_barrier(); - - /* Quick exit if already set */ - if (latch->is_set) - return; - - latch->is_set = true; - - /* - * See if anyone's waiting for the latch. It can be the current process if - * we're in a signal handler. - * - * Use a local variable here just in case somebody changes the event field - * concurrently (which really should not happen). - */ - handle = latch->event; - if (handle) - { - SetEvent(handle); - - /* - * Note that we silently ignore any errors. We might be in a signal - * handler or other critical path where it's not safe to call elog(). - */ - } -} - -void -ResetLatch(volatile Latch *latch) -{ - /* Only the owner should reset the latch */ - Assert(latch->owner_pid == MyProcPid); - - latch->is_set = false; - - /* - * Ensure that the write to is_set gets flushed to main memory before we - * examine any flag variables. Otherwise a concurrent SetLatch might - * falsely conclude that it needn't signal us, even though we have missed - * seeing some flag updates that SetLatch was supposed to inform us of. - */ - pg_memory_barrier(); -} diff --git a/src/backend/storage/ipc/Makefile b/src/backend/storage/ipc/Makefile index d8eb74244e2..8a55392adea 100644 --- a/src/backend/storage/ipc/Makefile +++ b/src/backend/storage/ipc/Makefile @@ -8,7 +8,8 @@ subdir = src/backend/storage/ipc top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global -OBJS = dsm_impl.o dsm.o ipc.o ipci.o pmsignal.o procarray.o procsignal.o \ - shmem.o shmqueue.o shm_mq.o shm_toc.o sinval.o sinvaladt.o standby.o +OBJS = dsm_impl.o dsm.o ipc.o ipci.o latch.o pmsignal.o procarray.o \ + procsignal.o shmem.o shmqueue.o shm_mq.o shm_toc.o sinval.o \ + sinvaladt.o standby.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/port/unix_latch.c b/src/backend/storage/ipc/latch.c similarity index 74% rename from src/backend/port/unix_latch.c rename to src/backend/storage/ipc/latch.c index 63b76c650f0..d42c9c6fdf1 100644 --- a/src/backend/port/unix_latch.c +++ b/src/backend/storage/ipc/latch.c @@ -1,6 +1,6 @@ /*------------------------------------------------------------------------- * - * unix_latch.c + * latch.c * Routines for inter-process latches * * The Unix implementation uses the so-called self-pipe trick to overcome @@ -22,11 +22,14 @@ * process, SIGUSR1 is sent and the signal handler in the waiting process * writes the byte to the pipe on behalf of the signaling process. * + * The Windows implementation uses Windows events that are inherited by + * all postmaster child processes. + * * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * src/backend/port/unix_latch.c + * src/backend/storage/ipc/latch.c * *------------------------------------------------------------------------- */ @@ -62,16 +65,20 @@ * useful to manually specify the used primitive. If desired, just add a * define somewhere before this block. */ -#if defined(LATCH_USE_POLL) || defined(LATCH_USE_SELECT) +#if defined(LATCH_USE_POLL) || defined(LATCH_USE_SELECT) \ + || defined(LATCH_USE_WIN32) /* don't overwrite manual choice */ #elif defined(HAVE_POLL) #define LATCH_USE_POLL #elif HAVE_SYS_SELECT_H #define LATCH_USE_SELECT +#elif WIN32 +#define LATCH_USE_WIN32 #else #error "no latch implementation available" #endif +#ifndef WIN32 /* Are we currently in WaitLatch? The signal handler would like to know. */ static volatile sig_atomic_t waiting = false; @@ -82,6 +89,7 @@ static int selfpipe_writefd = -1; /* Private function prototypes */ static void sendSelfPipeByte(void); static void drainSelfPipe(void); +#endif /* WIN32 */ /* @@ -93,6 +101,7 @@ static void drainSelfPipe(void); void InitializeLatchSupport(void) { +#ifndef WIN32 int pipefd[2]; Assert(selfpipe_readfd == -1); @@ -113,6 +122,9 @@ InitializeLatchSupport(void) selfpipe_readfd = pipefd[0]; selfpipe_writefd = pipefd[1]; +#else + /* currently, nothing to do here for Windows */ +#endif } /* @@ -121,12 +133,18 @@ InitializeLatchSupport(void) void InitLatch(volatile Latch *latch) { - /* Assert InitializeLatchSupport has been called in this process */ - Assert(selfpipe_readfd >= 0); - latch->is_set = false; latch->owner_pid = MyProcPid; latch->is_shared = false; + +#ifndef WIN32 + /* Assert InitializeLatchSupport has been called in this process */ + Assert(selfpipe_readfd >= 0); +#else + latch->event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (latch->event == NULL) + elog(ERROR, "CreateEvent failed: error code %lu", GetLastError()); +#endif /* WIN32 */ } /* @@ -143,6 +161,21 @@ InitLatch(volatile Latch *latch) void InitSharedLatch(volatile Latch *latch) { +#ifdef WIN32 + SECURITY_ATTRIBUTES sa; + + /* + * Set up security attributes to specify that the events are inherited. + */ + ZeroMemory(&sa, sizeof(sa)); + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + + latch->event = CreateEvent(&sa, TRUE, FALSE, NULL); + if (latch->event == NULL) + elog(ERROR, "CreateEvent failed: error code %lu", GetLastError()); +#endif + latch->is_set = false; latch->owner_pid = 0; latch->is_shared = true; @@ -164,12 +197,14 @@ InitSharedLatch(volatile Latch *latch) void OwnLatch(volatile Latch *latch) { - /* Assert InitializeLatchSupport has been called in this process */ - Assert(selfpipe_readfd >= 0); - + /* Sanity checks */ Assert(latch->is_shared); - /* sanity check */ +#ifndef WIN32 + /* Assert InitializeLatchSupport has been called in this process */ + Assert(selfpipe_readfd >= 0); +#endif + if (latch->owner_pid != 0) elog(ERROR, "latch already owned"); @@ -221,6 +256,7 @@ WaitLatch(volatile Latch *latch, int wakeEvents, long timeout) * returning the socket as readable/writable or both, depending on * WL_SOCKET_READABLE/WL_SOCKET_WRITEABLE being specified. */ +#ifndef LATCH_USE_WIN32 int WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, long timeout) @@ -551,6 +587,199 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, return result; } +#else /* LATCH_USE_WIN32 */ +int +WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, + long timeout) +{ + DWORD rc; + instr_time start_time, + cur_time; + long cur_timeout; + HANDLE events[4]; + HANDLE latchevent; + HANDLE sockevent = WSA_INVALID_EVENT; + int numevents; + int result = 0; + int pmdeath_eventno = 0; + + Assert(wakeEvents != 0); /* must have at least one wake event */ + + /* waiting for socket readiness without a socket indicates a bug */ + if (sock == PGINVALID_SOCKET && + (wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) != 0) + elog(ERROR, "cannot wait on socket event without a socket"); + + if ((wakeEvents & WL_LATCH_SET) && latch->owner_pid != MyProcPid) + elog(ERROR, "cannot wait on a latch owned by another process"); + + /* + * Initialize timeout if requested. We must record the current time so + * that we can determine the remaining timeout if WaitForMultipleObjects + * is interrupted. + */ + if (wakeEvents & WL_TIMEOUT) + { + INSTR_TIME_SET_CURRENT(start_time); + Assert(timeout >= 0 && timeout <= INT_MAX); + cur_timeout = timeout; + } + else + cur_timeout = INFINITE; + + /* + * Construct an array of event handles for WaitforMultipleObjects(). + * + * Note: pgwin32_signal_event should be first to ensure that it will be + * reported when multiple events are set. We want to guarantee that + * pending signals are serviced. + */ + latchevent = latch->event; + + events[0] = pgwin32_signal_event; + events[1] = latchevent; + numevents = 2; + if (wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) + { + /* Need an event object to represent events on the socket */ + int flags = FD_CLOSE; /* always check for errors/EOF */ + + if (wakeEvents & WL_SOCKET_READABLE) + flags |= FD_READ; + if (wakeEvents & WL_SOCKET_WRITEABLE) + flags |= FD_WRITE; + + sockevent = WSACreateEvent(); + if (sockevent == WSA_INVALID_EVENT) + elog(ERROR, "failed to create event for socket: error code %u", + WSAGetLastError()); + if (WSAEventSelect(sock, sockevent, flags) != 0) + elog(ERROR, "failed to set up event for socket: error code %u", + WSAGetLastError()); + + events[numevents++] = sockevent; + } + if (wakeEvents & WL_POSTMASTER_DEATH) + { + pmdeath_eventno = numevents; + events[numevents++] = PostmasterHandle; + } + + /* Ensure that signals are serviced even if latch is already set */ + pgwin32_dispatch_queued_signals(); + + do + { + /* + * The comment in the unix version above applies here as well. At + * least after mentally replacing self-pipe with windows event. + * There's no danger of overflowing, as "Setting an event that is + * already set has no effect.". + */ + if ((wakeEvents & WL_LATCH_SET) && latch->is_set) + { + result |= WL_LATCH_SET; + + /* + * Leave loop immediately, avoid blocking again. We don't attempt + * to report any other events that might also be satisfied. + */ + break; + } + + rc = WaitForMultipleObjects(numevents, events, FALSE, cur_timeout); + + if (rc == WAIT_FAILED) + elog(ERROR, "WaitForMultipleObjects() failed: error code %lu", + GetLastError()); + else if (rc == WAIT_TIMEOUT) + { + result |= WL_TIMEOUT; + } + else if (rc == WAIT_OBJECT_0) + { + /* Service newly-arrived signals */ + pgwin32_dispatch_queued_signals(); + } + else if (rc == WAIT_OBJECT_0 + 1) + { + /* + * Reset the event. We'll re-check the, potentially, set latch on + * next iteration of loop, but let's not waste the cycles to + * update cur_timeout below. + */ + if (!ResetEvent(latchevent)) + elog(ERROR, "ResetEvent failed: error code %lu", GetLastError()); + + continue; + } + else if ((wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) && + rc == WAIT_OBJECT_0 + 2) /* socket is at event slot 2 */ + { + WSANETWORKEVENTS resEvents; + + ZeroMemory(&resEvents, sizeof(resEvents)); + if (WSAEnumNetworkEvents(sock, sockevent, &resEvents) != 0) + elog(ERROR, "failed to enumerate network events: error code %u", + WSAGetLastError()); + if ((wakeEvents & WL_SOCKET_READABLE) && + (resEvents.lNetworkEvents & FD_READ)) + { + result |= WL_SOCKET_READABLE; + } + if ((wakeEvents & WL_SOCKET_WRITEABLE) && + (resEvents.lNetworkEvents & FD_WRITE)) + { + result |= WL_SOCKET_WRITEABLE; + } + if (resEvents.lNetworkEvents & FD_CLOSE) + { + if (wakeEvents & WL_SOCKET_READABLE) + result |= WL_SOCKET_READABLE; + if (wakeEvents & WL_SOCKET_WRITEABLE) + result |= WL_SOCKET_WRITEABLE; + } + } + else if ((wakeEvents & WL_POSTMASTER_DEATH) && + rc == WAIT_OBJECT_0 + pmdeath_eventno) + { + /* + * Postmaster apparently died. Since the consequences of falsely + * returning WL_POSTMASTER_DEATH could be pretty unpleasant, we + * take the trouble to positively verify this with + * PostmasterIsAlive(), even though there is no known reason to + * think that the event could be falsely set on Windows. + */ + if (!PostmasterIsAlive()) + result |= WL_POSTMASTER_DEATH; + } + else + elog(ERROR, "unexpected return code from WaitForMultipleObjects(): %lu", rc); + + /* If we're not done, update cur_timeout for next iteration */ + if (result == 0 && (wakeEvents & WL_TIMEOUT)) + { + INSTR_TIME_SET_CURRENT(cur_time); + INSTR_TIME_SUBTRACT(cur_time, start_time); + cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time); + if (cur_timeout <= 0) + { + /* Timeout has expired, no need to continue looping */ + result |= WL_TIMEOUT; + } + } + } while (result == 0); + + /* Clean up the event object we created for the socket */ + if (sockevent != WSA_INVALID_EVENT) + { + WSAEventSelect(sock, NULL, 0); + WSACloseEvent(sockevent); + } + + return result; +} +#endif /* LATCH_USE_WIN32 */ /* * Sets a latch and wakes up anyone waiting on it. @@ -567,7 +796,11 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, void SetLatch(volatile Latch *latch) { +#ifndef WIN32 pid_t owner_pid; +#else + HANDLE handle; +#endif /* * The memory barrier has be to be placed here to ensure that any flag @@ -582,6 +815,8 @@ SetLatch(volatile Latch *latch) latch->is_set = true; +#ifndef WIN32 + /* * See if anyone's waiting for the latch. It can be the current process if * we're in a signal handler. We use the self-pipe to wake up the select() @@ -613,6 +848,27 @@ SetLatch(volatile Latch *latch) } else kill(owner_pid, SIGUSR1); +#else + + /* + * See if anyone's waiting for the latch. It can be the current process if + * we're in a signal handler. + * + * Use a local variable here just in case somebody changes the event field + * concurrently (which really should not happen). + */ + handle = latch->event; + if (handle) + { + SetEvent(handle); + + /* + * Note that we silently ignore any errors. We might be in a signal + * handler or other critical path where it's not safe to call elog(). + */ + } +#endif + } /* @@ -646,14 +902,17 @@ ResetLatch(volatile Latch *latch) * NB: when calling this in a signal handler, be sure to save and restore * errno around it. */ +#ifndef WIN32 void latch_sigusr1_handler(void) { if (waiting) sendSelfPipeByte(); } +#endif /* !WIN32 */ /* Send one byte to the self-pipe, to wake up WaitLatch */ +#ifndef WIN32 static void sendSelfPipeByte(void) { @@ -683,6 +942,7 @@ retry: return; } } +#endif /* !WIN32 */ /* * Read all available data from the self-pipe @@ -691,6 +951,7 @@ retry: * return, it must reset that flag first (though ideally, this will never * happen). */ +#ifndef WIN32 static void drainSelfPipe(void) { @@ -729,3 +990,4 @@ drainSelfPipe(void) /* else buffer wasn't big enough, so read again */ } } +#endif /* !WIN32 */ diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index 737e11d0168..1b9521f5a69 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -36,7 +36,7 @@ * WaitLatch includes a provision for timeouts (which should be avoided * when possible, as they incur extra overhead) and a provision for * postmaster child processes to wake up immediately on postmaster death. - * See unix_latch.c for detailed specifications for the exported functions. + * See latch.c for detailed specifications for the exported functions. * * The correct pattern to wait for event(s) is: * diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index ab65fa3085e..012b327d9d2 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -136,8 +136,6 @@ sub mkvcbuild 'src/backend/port/win32_sema.c'); $postgres->ReplaceFile('src/backend/port/pg_shmem.c', 'src/backend/port/win32_shmem.c'); - $postgres->ReplaceFile('src/backend/port/pg_latch.c', - 'src/backend/port/win32_latch.c'); $postgres->AddFiles('src/port', @pgportfiles); $postgres->AddFiles('src/common', @pgcommonbkndfiles); $postgres->AddDir('src/timezone');