Skip to content

Commit 6148656

Browse files
committed
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
1 parent 6a2a70a commit 6148656

File tree

1 file changed

+38
-17
lines changed

1 file changed

+38
-17
lines changed

src/backend/storage/ipc/latch.c

+38-17
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
* don't need to register a signal handler or create our own self-pipe. We
1919
* assume that any system that has Linux epoll() also has Linux signalfd().
2020
*
21+
* The kqueue() implementation waits for SIGURG with EVFILT_SIGNAL.
22+
*
2123
* The Windows implementation uses Windows events that are inherited by all
2224
* postmaster child processes. There's no need for the self-pipe trick there.
2325
*
@@ -150,7 +152,7 @@ static volatile sig_atomic_t waiting = false;
150152
static int signal_fd = -1;
151153
#endif
152154

153-
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
155+
#if defined(WAIT_USE_POLL)
154156
/* Read and write ends of the self-pipe */
155157
static int selfpipe_readfd = -1;
156158
static int selfpipe_writefd = -1;
@@ -189,7 +191,7 @@ static inline int WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
189191
void
190192
InitializeLatchSupport(void)
191193
{
192-
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
194+
#if defined(WAIT_USE_POLL)
193195
int pipefd[2];
194196

195197
if (IsUnderPostmaster)
@@ -277,6 +279,11 @@ InitializeLatchSupport(void)
277279
elog(FATAL, "signalfd() failed");
278280
ReserveExternalFD();
279281
#endif
282+
283+
#ifdef WAIT_USE_KQUEUE
284+
/* Ignore SIGURG, because we'll receive it via kqueue. */
285+
pqsignal(SIGURG, SIG_IGN);
286+
#endif
280287
}
281288

282289
void
@@ -300,7 +307,7 @@ InitializeLatchWaitSet(void)
300307
void
301308
ShutdownLatchSupport(void)
302309
{
303-
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
310+
#if defined(WAIT_USE_POLL)
304311
pqsignal(SIGURG, SIG_IGN);
305312
#endif
306313

@@ -310,7 +317,7 @@ ShutdownLatchSupport(void)
310317
LatchWaitSet = NULL;
311318
}
312319

313-
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
320+
#if defined(WAIT_USE_POLL)
314321
close(selfpipe_readfd);
315322
close(selfpipe_writefd);
316323
selfpipe_readfd = -1;
@@ -335,7 +342,7 @@ InitLatch(Latch *latch)
335342
latch->owner_pid = MyProcPid;
336343
latch->is_shared = false;
337344

338-
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
345+
#if defined(WAIT_USE_POLL)
339346
/* Assert InitializeLatchSupport has been called in this process */
340347
Assert(selfpipe_readfd >= 0 && selfpipe_owner_pid == MyProcPid);
341348
#elif defined(WAIT_USE_WIN32)
@@ -399,7 +406,7 @@ OwnLatch(Latch *latch)
399406
/* Sanity checks */
400407
Assert(latch->is_shared);
401408

402-
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
409+
#if defined(WAIT_USE_POLL)
403410
/* Assert InitializeLatchSupport has been called in this process */
404411
Assert(selfpipe_readfd >= 0 && selfpipe_owner_pid == MyProcPid);
405412
#endif
@@ -611,7 +618,7 @@ SetLatch(Latch *latch)
611618
return;
612619
else if (owner_pid == MyProcPid)
613620
{
614-
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
621+
#if defined(WAIT_USE_POLL)
615622
if (waiting)
616623
sendSelfPipeByte();
617624
#else
@@ -898,13 +905,15 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
898905
{
899906
set->latch = latch;
900907
set->latch_pos = event->pos;
901-
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
908+
#if defined(WAIT_USE_POLL)
902909
event->fd = selfpipe_readfd;
903910
#elif defined(WAIT_USE_EPOLL)
904911
event->fd = signal_fd;
905912
#else
906913
event->fd = PGINVALID_SOCKET;
914+
#ifdef WAIT_USE_EPOLL
907915
return event->pos;
916+
#endif
908917
#endif
909918
}
910919
else if (events == WL_POSTMASTER_DEATH)
@@ -1125,6 +1134,18 @@ WaitEventAdjustKqueueAddPostmaster(struct kevent *k_ev, WaitEvent *event)
11251134
AccessWaitEvent(k_ev) = event;
11261135
}
11271136

1137+
static inline void
1138+
WaitEventAdjustKqueueAddLatch(struct kevent *k_ev, WaitEvent *event)
1139+
{
1140+
/* For now latch can only be added, not removed. */
1141+
k_ev->ident = SIGURG;
1142+
k_ev->filter = EVFILT_SIGNAL;
1143+
k_ev->flags = EV_ADD;
1144+
k_ev->fflags = 0;
1145+
k_ev->data = 0;
1146+
AccessWaitEvent(k_ev) = event;
1147+
}
1148+
11281149
/*
11291150
* old_events is the previous event mask, used to compute what has changed.
11301151
*/
@@ -1156,18 +1177,21 @@ WaitEventAdjustKqueue(WaitEventSet *set, WaitEvent *event, int old_events)
11561177
*/
11571178
WaitEventAdjustKqueueAddPostmaster(&k_ev[count++], event);
11581179
}
1180+
else if (event->events == WL_LATCH_SET)
1181+
{
1182+
/* We detect latch wakeup using a signal event. */
1183+
WaitEventAdjustKqueueAddLatch(&k_ev[count++], event);
1184+
}
11591185
else
11601186
{
11611187
/*
11621188
* We need to compute the adds and deletes required to get from the
11631189
* old event mask to the new event mask, since kevent treats readable
11641190
* and writable as separate events.
11651191
*/
1166-
if (old_events == WL_LATCH_SET ||
1167-
(old_events & WL_SOCKET_READABLE))
1192+
if (old_events & WL_SOCKET_READABLE)
11681193
old_filt_read = true;
1169-
if (event->events == WL_LATCH_SET ||
1170-
(event->events & WL_SOCKET_READABLE))
1194+
if (event->events & WL_SOCKET_READABLE)
11711195
new_filt_read = true;
11721196
if (old_events & WL_SOCKET_WRITEABLE)
11731197
old_filt_write = true;
@@ -1620,11 +1644,8 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
16201644
occurred_events->events = 0;
16211645

16221646
if (cur_event->events == WL_LATCH_SET &&
1623-
cur_kqueue_event->filter == EVFILT_READ)
1647+
cur_kqueue_event->filter == EVFILT_SIGNAL)
16241648
{
1625-
/* There's data in the self-pipe, clear it. */
1626-
drain();
1627-
16281649
if (set->latch && set->latch->is_set)
16291650
{
16301651
occurred_events->fd = PGINVALID_SOCKET;
@@ -1999,7 +2020,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
19992020
}
20002021
#endif
20012022

2002-
#if defined(WAIT_USE_POLL) || defined(WAIT_USE_KQUEUE)
2023+
#if defined(WAIT_USE_POLL)
20032024

20042025
/*
20052026
* SetLatch uses SIGURG to wake up the process waiting on the latch.

0 commit comments

Comments
 (0)