#include "postgres.h"
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <unistd.h>
#include "miscadmin.h"
#include "portability/instr_time.h"
#include "postmaster/postmaster.h"
#include "storage/latch.h"
#include "storage/pmsignal.h"
#include "storage/shmem.h"
Go to the source code of this file.
Functions | |
void | InitializeLatchSupport (void) |
void | InitLatch (volatile Latch *latch) |
void | InitSharedLatch (volatile Latch *latch) |
void | OwnLatch (volatile Latch *latch) |
void | DisownLatch (volatile Latch *latch) |
int | WaitLatch (volatile Latch *latch, int wakeEvents, long timeout) |
int | WaitLatchOrSocket (volatile Latch *latch, int wakeEvents, pgsocket sock, long timeout) |
void | SetLatch (volatile Latch *latch) |
void | ResetLatch (volatile Latch *latch) |
void DisownLatch | ( | volatile Latch * | latch | ) |
Definition at line 86 of file win32_latch.c.
References Assert, Latch::is_shared, MyProcPid, and Latch::owner_pid.
void InitializeLatchSupport | ( | void | ) |
Definition at line 36 of file win32_latch.c.
References Assert, elog, FATAL, selfpipe_readfd, and selfpipe_writefd.
{
/* currently, nothing to do here for Windows */
}
void InitLatch | ( | volatile Latch * | latch | ) |
Definition at line 42 of file win32_latch.c.
References Assert, elog, ERROR, FALSE, Latch::is_set, Latch::is_shared, MyProcPid, NULL, Latch::owner_pid, selfpipe_readfd, and TRUE.
void InitSharedLatch | ( | volatile Latch * | latch | ) |
Definition at line 54 of file win32_latch.c.
References elog, ERROR, FALSE, Latch::is_set, Latch::is_shared, NULL, Latch::owner_pid, and TRUE.
{ 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 | ) |
Definition at line 75 of file win32_latch.c.
References Assert, elog, ERROR, Latch::is_shared, MyProcPid, Latch::owner_pid, and selfpipe_readfd.
void ResetLatch | ( | volatile Latch * | latch | ) |
Definition at line 317 of file win32_latch.c.
References Assert, Latch::is_set, MyProcPid, and Latch::owner_pid.
void SetLatch | ( | volatile Latch * | latch | ) |
Definition at line 287 of file win32_latch.c.
References Latch::is_set, MyProcPid, Latch::owner_pid, sendSelfPipeByte(), SIGUSR1, and waiting.
{ HANDLE handle; /* 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(). */ } }
int WaitLatch | ( | volatile Latch * | latch, | |
int | wakeEvents, | |||
long | timeout | |||
) |
Definition at line 95 of file win32_latch.c.
References PGINVALID_SOCKET, and WaitLatchOrSocket().
{ return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout); }
Definition at line 101 of file win32_latch.c.
References Assert, drainSelfPipe(), EINTR, elog, ereport, errcode_for_socket_access(), errmsg(), ERROR, FALSE, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, Latch::is_set, MyProcPid, NULL, Latch::owner_pid, PGINVALID_SOCKET, pgwin32_dispatch_queued_signals(), pgwin32_signal_event, postmaster_alive_fds, POSTMASTER_FD_WATCH, PostmasterIsAlive(), select, selfpipe_readfd, start_time, waiting, WL_LATCH_SET, WL_POSTMASTER_DEATH, WL_SOCKET_READABLE, WL_SOCKET_WRITEABLE, and WL_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; /* Ignore WL_SOCKET_* events if no valid socket is given */ if (sock == PGINVALID_SOCKET) wakeEvents &= ~(WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE); Assert(wakeEvents != 0); /* must have at least one wake event */ /* Cannot specify WL_SOCKET_WRITEABLE without WL_SOCKET_READABLE */ Assert((wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) != WL_SOCKET_WRITEABLE); 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 = 0; if (wakeEvents & WL_SOCKET_READABLE) flags |= (FD_READ | FD_CLOSE); 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 { /* * Reset the event, and check if the latch is set already. If someone * sets the latch between this and the WaitForMultipleObjects() call * below, the setter will set the event and WaitForMultipleObjects() * will return immediately. */ if (!ResetEvent(latchevent)) elog(ERROR, "ResetEvent failed: error code %lu", GetLastError()); 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) { /* * Latch is set. We'll handle that on next iteration of loop, but * let's not waste the cycles to update cur_timeout below. */ 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 | FD_CLOSE))) { result |= WL_SOCKET_READABLE; } if ((wakeEvents & WL_SOCKET_WRITEABLE) && (resEvents.lNetworkEvents & FD_WRITE)) { 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 && cur_timeout != INFINITE) { 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) cur_timeout = 0; } } 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; }