aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Munro <tmunro@postgresql.org>2021-03-01 12:28:43 +1300
committerThomas Munro <tmunro@postgresql.org>2021-03-01 14:20:04 +1300
commit6148656a0be1c6245fbcfcbbeb87541f1b173162 (patch)
treedc1f6132f8f21ea2c7c234930cc1ea0fa17253dc
parent6a2a70a02018d6362f9841cc2f499cc45405e86b (diff)
downloadpostgresql-6148656a0be1c6245fbcfcbbeb87541f1b173162.tar.gz
postgresql-6148656a0be1c6245fbcfcbbeb87541f1b173162.zip
Use EVFILT_SIGNAL for kqueue latches.
Cut down on system calls and other overheads by waiting for SIGURG explicitly with kqueue instead of using a signal handler and self-pipe. Affects *BSD and macOS systems. This leaves only the poll implementation with a signal handler and the traditional self-pipe trick. Discussion: https://postgr.es/m/CA+hUKGJjxPDpzBE0a3hyUywBvaZuC89yx3jK9RFZgfv_KHU7gg@mail.gmail.com
-rw-r--r--src/backend/storage/ipc/latch.c55
1 files changed, 38 insertions, 17 deletions
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index ea6d9948abe..43a5fded103 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -18,6 +18,8 @@
* don't need to register a signal handler or create our own self-pipe. We
* assume that any system that has Linux epoll() also has Linux signalfd().
*
+ * The kqueue() implementation waits for SIGURG with EVFILT_SIGNAL.
+ *
* The Windows implementation uses Windows events that are inherited by all
* postmaster child processes. There's no need for the self-pipe trick there.
*
@@ -150,7 +152,7 @@ static volatile sig_atomic_t waiting = false;
static int signal_fd = -1;
#endif
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
/* Read and write ends of the self-pipe */
static int selfpipe_readfd = -1;
static int selfpipe_writefd = -1;
@@ -189,7 +191,7 @@ static inline int WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
void
InitializeLatchSupport(void)
{
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
int pipefd[2];
if (IsUnderPostmaster)
@@ -277,6 +279,11 @@ InitializeLatchSupport(void)
elog(FATAL, "signalfd() failed");
ReserveExternalFD();
#endif
+
+#ifdef WAIT_USE_KQUEUE
+ /* Ignore SIGURG, because we'll receive it via kqueue. */
+ pqsignal(SIGURG, SIG_IGN);
+#endif
}
void
@@ -300,7 +307,7 @@ InitializeLatchWaitSet(void)
void
ShutdownLatchSupport(void)
{
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
pqsignal(SIGURG, SIG_IGN);
#endif
@@ -310,7 +317,7 @@ ShutdownLatchSupport(void)
LatchWaitSet = NULL;
}
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
close(selfpipe_readfd);
close(selfpipe_writefd);
selfpipe_readfd = -1;
@@ -335,7 +342,7 @@ InitLatch(Latch *latch)
latch->owner_pid = MyProcPid;
latch->is_shared = false;
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
/* Assert InitializeLatchSupport has been called in this process */
Assert(selfpipe_readfd >= 0 && selfpipe_owner_pid == MyProcPid);
#elif defined(WAIT_USE_WIN32)
@@ -399,7 +406,7 @@ OwnLatch(Latch *latch)
/* Sanity checks */
Assert(latch->is_shared);
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
/* Assert InitializeLatchSupport has been called in this process */
Assert(selfpipe_readfd >= 0 && selfpipe_owner_pid == MyProcPid);
#endif
@@ -611,7 +618,7 @@ SetLatch(Latch *latch)
return;
else if (owner_pid == MyProcPid)
{
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
if (waiting)
sendSelfPipeByte();
#else
@@ -898,14 +905,16 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
{
set->latch = latch;
set->latch_pos = event->pos;
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
event->fd = selfpipe_readfd;
#elif defined(WAIT_USE_EPOLL)
event->fd = signal_fd;
#else
event->fd = PGINVALID_SOCKET;
+#ifdef WAIT_USE_EPOLL
return event->pos;
#endif
+#endif
}
else if (events == WL_POSTMASTER_DEATH)
{
@@ -1125,6 +1134,18 @@ WaitEventAdjustKqueueAddPostmaster(struct kevent *k_ev, WaitEvent *event)
AccessWaitEvent(k_ev) = event;
}
+static inline void
+WaitEventAdjustKqueueAddLatch(struct kevent *k_ev, WaitEvent *event)
+{
+ /* For now latch can only be added, not removed. */
+ k_ev->ident = SIGURG;
+ k_ev->filter = EVFILT_SIGNAL;
+ k_ev->flags = EV_ADD;
+ k_ev->fflags = 0;
+ k_ev->data = 0;
+ AccessWaitEvent(k_ev) = event;
+}
+
/*
* old_events is the previous event mask, used to compute what has changed.
*/
@@ -1156,6 +1177,11 @@ WaitEventAdjustKqueue(WaitEventSet *set, WaitEvent *event, int old_events)
*/
WaitEventAdjustKqueueAddPostmaster(&k_ev[count++], event);
}
+ else if (event->events == WL_LATCH_SET)
+ {
+ /* We detect latch wakeup using a signal event. */
+ WaitEventAdjustKqueueAddLatch(&k_ev[count++], event);
+ }
else
{
/*
@@ -1163,11 +1189,9 @@ WaitEventAdjustKqueue(WaitEventSet *set, WaitEvent *event, int old_events)
* old event mask to the new event mask, since kevent treats readable
* and writable as separate events.
*/
- if (old_events == WL_LATCH_SET ||
- (old_events & WL_SOCKET_READABLE))
+ if (old_events & WL_SOCKET_READABLE)
old_filt_read = true;
- if (event->events == WL_LATCH_SET ||
- (event->events & WL_SOCKET_READABLE))
+ if (event->events & WL_SOCKET_READABLE)
new_filt_read = true;
if (old_events & WL_SOCKET_WRITEABLE)
old_filt_write = true;
@@ -1620,11 +1644,8 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
occurred_events->events = 0;
if (cur_event->events == WL_LATCH_SET &&
- cur_kqueue_event->filter == EVFILT_READ)
+ cur_kqueue_event->filter == EVFILT_SIGNAL)
{
- /* There's data in the self-pipe, clear it. */
- drain();
-
if (set->latch && set->latch->is_set)
{
occurred_events->fd = PGINVALID_SOCKET;
@@ -1999,7 +2020,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
}
#endif
-#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
+#if defined(WAIT_USE_POLL)
/*
* SetLatch uses SIGURG to wake up the process waiting on the latch.