#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;
}
1.7.1