Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w7TXR-005LyW-07 for pgsql-hackers@arkaria.postgresql.org; Tue, 31 Mar 2026 07:29:25 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w7TXP-008Vd3-1V for pgsql-hackers@arkaria.postgresql.org; Tue, 31 Mar 2026 07:29:23 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w7TXP-008Vcu-0N for pgsql-hackers@lists.postgresql.org; Tue, 31 Mar 2026 07:29:23 +0000 Received: from mail-pl1-x635.google.com ([2607:f8b0:4864:20::635]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1w7TXM-000000028Em-2k0i for pgsql-hackers@lists.postgresql.org; Tue, 31 Mar 2026 07:29:23 +0000 Received: by mail-pl1-x635.google.com with SMTP id d9443c01a7336-2b2503753efso16558385ad.0 for ; Tue, 31 Mar 2026 00:29:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774942158; x=1775546958; darn=lists.postgresql.org; h=to:date:message-id:subject:mime-version:from:from:to:cc:subject :date:message-id:reply-to; bh=onEjoFwvpz7LMuV7WYPFBQb0biJwwP0cUq5QJeg9A2M=; b=evFyswI3vJRezfiYQI3LS9ljwIksVL9ppRJn0V5dCaLwGPtGVyPtv6qK1+AN6zucY6 FcdwIN9Z6vW2iVLYqZpUxlTg1fn+kubtbG9ub9QRLeHAa7L7Qvi43iCoxymKWim/edmN cr5+dgCqquiStcT0rh73QpQ30PDyuB0u+dlj/VeRkzbphwrozfS86jfvxM+SFapeppu7 nSeL5XIuIlS+rSRhEmgTZ36cTzAS/7vLNwGXusLm3jR1yuMHmfGU3vVZLNcvnKHkf57H ec82hoI2Bt6sjeSgWpbPbutxGbChNDrj0FVw1/ViHpFT1ewABXibbj+fPPxztnQmyJF7 rclA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774942158; x=1775546958; h=to:date:message-id:subject:mime-version:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=onEjoFwvpz7LMuV7WYPFBQb0biJwwP0cUq5QJeg9A2M=; b=lAPFqfaa6/9WzAXuTVQnhyn589qySNZjooxAFq1/yxiQANsz7STU+lC5vsEvPXdYVS htTuwaW0gqfbivUTyzpzBeGFbVshuGGow+/foNEQDPxXaR3Re+PXDKY++5N6hDa0tSM8 Uz+k8EyJqHKAGYGyiUOWTstAH6cADC3nA+9omzYSN7OA4TrVIdFBynkFzkqICJBi94xy E7goeQM4/9tuGwF0azB6EIxyyxcq923Y9kN38fkKgCZDlNr2GnC1b7j6tgDNJp3DZZ1I rjxaeHXgaxIZTRiSU01wuAXghfiwetN/cKYo7NM6ZUO1eFdI1igIihvXSdURJovFu4nS k/rw== X-Gm-Message-State: AOJu0Yyqy+j7DDT6404gCur2MUcVd8fSXH2xzghBdUTsH+n7YDCq6foP rt80jJYZW484LO6eKb2i4cVUI1BIjVKEhStnXR2Uy4PjYBp8PjX1Sbx9iY96aiWtvyc= X-Gm-Gg: ATEYQzwnPMAB5mjyEJ2vOqmoJoagZQkTnQ8cO5R2vyTQTVh6UG8JRrCyeOVwbx/Ls1a +Z+ZQKvMB0VwJmAIrdxcRmSaISvYly69bgwSVQTodK+rCdFfVG4jol4MitL5S+S53W5Wr3F8ISG eGcyFi2BWcoHt6TZFFqZ8O+TY162dnRBU9yNpOoB9eDtaF/DM0Dlx5V35xk9FwFG3sg/8xmLeH7 tx7+SgCj/Ltc1V4/6Iy8uxlA/cKXdegFpJBLKPTZ0c7QdBFhbFXTpSMFmJl1nDFR4y+lQYKrWJE 0XSkkLQWlKxnBmJAlS5bee8OSkdhggB67f3wGw+tydGh+RnEFsnPFCUFBMa1WPA5tdNYhyoWgYu 9bb5xavkYzm+OywZ/T1l2/5QtnmHKXl5AGiKI7K8vDyEBl2fZbzDrj0+IlXzXNN9jyLDRoOO6R6 YE2D1ExEx5wGPG6wQx5++H1yVnwWemIw== X-Received: by 2002:a17:902:e846:b0:2b2:490c:411e with SMTP id d9443c01a7336-2b2490c53c4mr100003625ad.6.1774942157700; Tue, 31 Mar 2026 00:29:17 -0700 (PDT) Received: from smtpclient.apple ([203.10.98.27]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b24278501esm106256195ad.58.2026.03.31.00.29.15 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 31 Mar 2026 00:29:16 -0700 (PDT) From: Chao Li Content-Type: multipart/mixed; boundary="Apple-Mail=_4A17D358-3B20-427B-9DDC-057D3AC4DFDC" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.400.21\)) Subject: PoC: Add condition variable support to WaitEventSetWait() Message-Id: Date: Tue, 31 Mar 2026 15:28:42 +0800 To: PostgreSQL Hackers X-Mailer: Apple Mail (2.3864.400.21) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_4A17D358-3B20-427B-9DDC-057D3AC4DFDC Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 Hi, There is an XXX comment in WalSndWait(): ``` * XXX: A desirable future improvement would be to add support for = CVs * into WaitEventSetWait(). ``` I have been exploring a possible approach for that. This patch is a PoC = that adds ConditionVariable support to WaitEventSet. This v1 is mainly = intended to gather feedback on the design, so I have only done some = basic testing so far, such as a normal logical replication workflow. I=E2=80=99d like to highlight a few key points about the design: 1. In the current WalSndWait(), although it prepares to sleep on a = ConditionVariable, it does not actually check whether the CV has been = signaled. In this PoC, I kept that same behavior. However, I tried to = make the WaitEventSet support for CVs generic, so that if we want to add = actual signal checking in the future, that would be possible. 2. To keep the design generic, this patch introduces a new wait event = type, WL_CONDITION_VARIABLE. A WL_CONDITION_VARIABLE event occupies a = position in the event array, similar to latch and socket events. When a = CV is signaled, the corresponding WL_CONDITION_VARIABLE event is = returned in occurred_events. 3. The WaitEventSet APIs AddWaitEventToSet() and ModifyWaitEvent() are = extended to support CVs by adding one more parameter =E2=80=9Ccv" to = both APIs. The downside of this approach is that all call sites of these = two APIs need to be updated. I also considered adding separate APIs for = CVs, such as AddWaitEventToSetForCV() and ModifyWaitEventForCV(), since = CVs do not rely on the kernel and it might therefore make sense to = decouple them from socket and latch handling. But for v1, I chose the = more generic approach. I=E2=80=99d be interested in hearing comments on = this part of the design. 4. One important point is that this patch extends the WaitEventSet = abstraction, not the underlying kernel wait primitives. A = ConditionVariable is still a userspace/shared-memory concept, but with = this design it can participate in the same waiting framework as sockets = and latches. I think that is useful because it allows mixed waits to be = handled through one interface. Here is the v1 patch. Best regards, -- Chao Li (Evan) HighGo Software Co., Ltd. https://www.highgo.com/ --Apple-Mail=_4A17D358-3B20-427B-9DDC-057D3AC4DFDC Content-Disposition: attachment; filename=v1-0001-Add-condition-variable-support-to-WaitEventSetWai.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v1-0001-Add-condition-variable-support-to-WaitEventSetWai.patch" Content-Transfer-Encoding: quoted-printable =46rom=208fe7d4382f4a6c28be01b40fdc3c1b834a214e09=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20"Chao=20Li=20(Evan)"=20=0A= Date:=20Tue,=2031=20Mar=202026=2008:25:12=20+0800=0ASubject:=20[PATCH=20= v1]=20Add=20condition=20variable=20support=20to=20WaitEventSetWait()=0A=0A= WalSndWait()=20currently=20combines=20WaitEventSetWait()=20with=20manual=0A= ConditionVariablePrepareToSleep()=20/=20ConditionVariableCancelSleep()=0A= calls.=0A=0AThis=20patch=20teaches=20WaitEventSetWait()=20to=20cooperate=20= with=20condition=0Avariables=20directly.=20A=20wait-event=20set=20can=20= now=20include=20a=20condition=0Avariable=20event,=20and=20= WaitEventSetWait()=20takes=20care=20of=20preparing=20to=0Asleep=20on=20= the=20condition=20variable=20before=20blocking=20and=20canceling=20the=0A= sleep=20afterwards.=0A=0AWith=20that=20in=20place,=20WalSndWait()=20no=20= longer=20needs=20to=20manage=20the=0Acondition-variable=20sleep=20state=20= manually,=20and=20can=20express=20the=20wakeup=0Asource=20through=20the=20= wait-event=20set=20itself.=0A=0AAuthor:=20Chao=20Li=20=0A= ---=0A=20src/backend/executor/nodeAppend.c=20=20=20=20=20=20=20=20=20=20=20= =20=20|=20=20=204=20+-=0A=20src/backend/libpq/be-secure.c=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20|=20=20=204=20+-=0A=20= src/backend/libpq/pqcomm.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20|=20=2012=20+-=0A=20src/backend/postmaster/postmaster.c=20=20= =20=20=20=20=20=20=20=20=20|=20=20=204=20+-=0A=20= src/backend/postmaster/syslogger.c=20=20=20=20=20=20=20=20=20=20=20=20|=20= =20=204=20+-=0A=20src/backend/replication/walsender.c=20=20=20=20=20=20=20= =20=20=20=20|=20=2017=20++-=0A=20src/backend/storage/ipc/latch.c=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20|=20=2016=20+--=0A=20= src/backend/storage/ipc/waiteventset.c=20=20=20=20=20=20=20=20|=20116=20= +++++++++++++++++-=0A=20src/backend/storage/lmgr/condition_variable.c=20= |=20=2033=20+++--=0A=20src/backend/utils/init/miscinit.c=20=20=20=20=20=20= =20=20=20=20=20=20=20|=20=20=204=20+-=0A=20src/include/libpq/libpq.h=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=203=20= +-=0A=20src/include/storage/condition_variable.h=20=20=20=20=20=20|=20=20= =201=20+=0A=20src/include/storage/waiteventset.h=20=20=20=20=20=20=20=20=20= =20=20=20|=20=20=207=20+-=0A=2013=20files=20changed,=20179=20= insertions(+),=2046=20deletions(-)=0A=0Adiff=20--git=20= a/src/backend/executor/nodeAppend.c=20= b/src/backend/executor/nodeAppend.c=0Aindex=2085c85569b5e..27895b96b50=20= 100644=0A---=20a/src/backend/executor/nodeAppend.c=0A+++=20= b/src/backend/executor/nodeAppend.c=0A@@=20-1045,7=20+1045,7=20@@=20= ExecAppendAsyncEventWait(AppendState=20*node)=0A=20=09= Assert(node->as_eventset=20=3D=3D=20NULL);=0A=20=09node->as_eventset=20=3D= =20CreateWaitEventSet(CurrentResourceOwner,=20nevents);=0A=20=09= AddWaitEventToSet(node->as_eventset,=20WL_EXIT_ON_PM_DEATH,=20= PGINVALID_SOCKET,=0A-=09=09=09=09=09=20=20NULL,=20NULL);=0A+=09=09=09=09=09= =20=20NULL,=20NULL,=20NULL);=0A=20=0A=20=09/*=20Give=20each=20waiting=20= subplan=20a=20chance=20to=20add=20an=20event.=20*/=0A=20=09i=20=3D=20-1;=0A= @@=20-1081,7=20+1081,7=20@@=20ExecAppendAsyncEventWait(AppendState=20= *node)=0A=20=09=20*=20extensions=20too.=0A=20=09=20*/=0A=20=09= AddWaitEventToSet(node->as_eventset,=20WL_LATCH_SET,=20PGINVALID_SOCKET,=0A= -=09=09=09=09=09=20=20MyLatch,=20NULL);=0A+=09=09=09=09=09=20=20MyLatch,=20= NULL,=20NULL);=0A=20=0A=20=09/*=20Return=20at=20most=20EVENT_BUFFER_SIZE=20= events=20in=20one=20call.=20*/=0A=20=09if=20(nevents=20>=20= EVENT_BUFFER_SIZE)=0Adiff=20--git=20a/src/backend/libpq/be-secure.c=20= b/src/backend/libpq/be-secure.c=0Aindex=20617704bb993..0a406a050d9=20= 100644=0A---=20a/src/backend/libpq/be-secure.c=0A+++=20= b/src/backend/libpq/be-secure.c=0A@@=20-217,7=20+217,7=20@@=20retry:=0A=20= =0A=20=09=09Assert(waitfor);=0A=20=0A-=09=09ModifyWaitEvent(FeBeWaitSet,=20= FeBeWaitSetSocketPos,=20waitfor,=20NULL);=0A+=09=09= ModifyWaitEvent(FeBeWaitSet,=20FeBeWaitSetSocketPos,=20waitfor,=20NULL,=20= NULL);=0A=20=0A=20=09=09WaitEventSetWait(FeBeWaitSet,=20-1=20/*=20no=20= timeout=20*/=20,=20&event,=201,=0A=20=09=09=09=09=09=09=20= WAIT_EVENT_CLIENT_READ);=0A@@=20-342,7=20+342,7=20@@=20retry:=0A=20=0A=20= =09=09Assert(waitfor);=0A=20=0A-=09=09ModifyWaitEvent(FeBeWaitSet,=20= FeBeWaitSetSocketPos,=20waitfor,=20NULL);=0A+=09=09= ModifyWaitEvent(FeBeWaitSet,=20FeBeWaitSetSocketPos,=20waitfor,=20NULL,=20= NULL);=0A=20=0A=20=09=09WaitEventSetWait(FeBeWaitSet,=20-1=20/*=20no=20= timeout=20*/=20,=20&event,=201,=0A=20=09=09=09=09=09=09=20= WAIT_EVENT_CLIENT_WRITE);=0Adiff=20--git=20a/src/backend/libpq/pqcomm.c=20= b/src/backend/libpq/pqcomm.c=0Aindex=204a442f22df6..5d3a5c22db0=20100644=0A= ---=20a/src/backend/libpq/pqcomm.c=0A+++=20b/src/backend/libpq/pqcomm.c=0A= @@=20-177,6=20+177,7=20@@=20pq_init(ClientSocket=20*client_sock)=0A=20=09= Port=09=20=20=20*port;=0A=20=09int=09=09=09socket_pos=20= PG_USED_FOR_ASSERTS_ONLY;=0A=20=09int=09=09=09latch_pos=20= PG_USED_FOR_ASSERTS_ONLY;=0A+=09int=09=09=09cv_pos=20= PG_USED_FOR_ASSERTS_ONLY;=0A=20=0A=20=09/*=20allocate=20the=20Port=20= struct=20and=20copy=20the=20ClientSocket=20contents=20to=20it=20*/=0A=20=09= port=20=3D=20palloc0_object(Port);=0A@@=20-307,11=20+308,13=20@@=20= pq_init(ClientSocket=20*client_sock)=0A=20=0A=20=09FeBeWaitSet=20=3D=20= CreateWaitEventSet(NULL,=20FeBeWaitSetNEvents);=0A=20=09socket_pos=20=3D=20= AddWaitEventToSet(FeBeWaitSet,=20WL_SOCKET_WRITEABLE,=0A-=09=09=09=09=09=09= =09=09=20=20=20port->sock,=20NULL,=20NULL);=0A+=09=09=09=09=09=09=09=09=20= =20=20port->sock,=20NULL,=20NULL,=20NULL);=0A=20=09latch_pos=20=3D=20= AddWaitEventToSet(FeBeWaitSet,=20WL_LATCH_SET,=20PGINVALID_SOCKET,=0A-=09= =09=09=09=09=09=09=09=20=20MyLatch,=20NULL);=0A+=09=09=09=09=09=09=09=09=20= =20MyLatch,=20NULL,=20NULL);=0A+=09cv_pos=20=3D=20= AddWaitEventToSet(FeBeWaitSet,=20WL_CONDITION_VARIABLE,=20= PGINVALID_SOCKET,=0A+=09=09=09=09=09=09=09=20=20=20NULL,=20NULL,=20= NULL);=0A=20=09AddWaitEventToSet(FeBeWaitSet,=20WL_POSTMASTER_DEATH,=20= PGINVALID_SOCKET,=0A-=09=09=09=09=09=20=20NULL,=20NULL);=0A+=09=09=09=09=09= =20=20NULL,=20NULL,=20NULL);=0A=20=0A=20=09/*=0A=20=09=20*=20The=20event=20= positions=20match=20the=20order=20we=20added=20them,=20but=20let's=20= sanity=0A@@=20-319,6=20+322,7=20@@=20pq_init(ClientSocket=20= *client_sock)=0A=20=09=20*/=0A=20=09Assert(socket_pos=20=3D=3D=20= FeBeWaitSetSocketPos);=0A=20=09Assert(latch_pos=20=3D=3D=20= FeBeWaitSetLatchPos);=0A+=09Assert(cv_pos=20=3D=3D=20FeBeWaitSetCVPos);=0A= =20=0A=20=09return=20port;=0A=20}=0A@@=20-2063,7=20+2067,7=20@@=20= pq_check_connection(void)=0A=20=09=20*=20It's=20OK=20to=20modify=20the=20= socket=20event=20filter=20without=20restoring,=20because=0A=20=09=20*=20= all=20FeBeWaitSet=20socket=20wait=20sites=20do=20the=20same.=0A=20=09=20= */=0A-=09ModifyWaitEvent(FeBeWaitSet,=20FeBeWaitSetSocketPos,=20= WL_SOCKET_CLOSED,=20NULL);=0A+=09ModifyWaitEvent(FeBeWaitSet,=20= FeBeWaitSetSocketPos,=20WL_SOCKET_CLOSED,=20NULL,=20NULL);=0A=20=0A=20= retry:=0A=20=09rc=20=3D=20WaitEventSetWait(FeBeWaitSet,=200,=20events,=20= lengthof(events),=200);=0Adiff=20--git=20= a/src/backend/postmaster/postmaster.c=20= b/src/backend/postmaster/postmaster.c=0Aindex=20abf0c97569e..f96cce8730d=20= 100644=0A---=20a/src/backend/postmaster/postmaster.c=0A+++=20= b/src/backend/postmaster/postmaster.c=0A@@=20-1638,13=20+1638,13=20@@=20= ConfigurePostmasterWaitSet(bool=20accept_connections)=0A=20=09= pm_wait_set=20=3D=20CreateWaitEventSet(NULL,=0A=20=09=09=09=09=09=09=09=09= =09=20accept_connections=20?=20(1=20+=20NumListenSockets)=20:=201);=0A=20= =09AddWaitEventToSet(pm_wait_set,=20WL_LATCH_SET,=20PGINVALID_SOCKET,=20= MyLatch,=0A-=09=09=09=09=09=20=20NULL);=0A+=09=09=09=09=09=20=20NULL,=20= NULL);=0A=20=0A=20=09if=20(accept_connections)=0A=20=09{=0A=20=09=09for=20= (int=20i=20=3D=200;=20i=20<=20NumListenSockets;=20i++)=0A=20=09=09=09= AddWaitEventToSet(pm_wait_set,=20WL_SOCKET_ACCEPT,=20ListenSockets[i],=0A= -=09=09=09=09=09=09=09=20=20NULL,=20NULL);=0A+=09=09=09=09=09=09=09=20=20= NULL,=20NULL,=20NULL);=0A=20=09}=0A=20}=0A=20=0Adiff=20--git=20= a/src/backend/postmaster/syslogger.c=20= b/src/backend/postmaster/syslogger.c=0Aindex=200c2a7bc8578..4db7df8e4a5=20= 100644=0A---=20a/src/backend/postmaster/syslogger.c=0A+++=20= b/src/backend/postmaster/syslogger.c=0A@@=20-338,9=20+338,9=20@@=20= SysLoggerMain(const=20void=20*startup_data,=20size_t=20startup_data_len)=0A= =20=09=20*=20(including=20the=20postmaster).=0A=20=09=20*/=0A=20=09wes=20= =3D=20CreateWaitEventSet(NULL,=202);=0A-=09AddWaitEventToSet(wes,=20= WL_LATCH_SET,=20PGINVALID_SOCKET,=20MyLatch,=20NULL);=0A+=09= AddWaitEventToSet(wes,=20WL_LATCH_SET,=20PGINVALID_SOCKET,=20MyLatch,=20= NULL,=20NULL);=0A=20#ifndef=20WIN32=0A-=09AddWaitEventToSet(wes,=20= WL_SOCKET_READABLE,=20syslogPipe[0],=20NULL,=20NULL);=0A+=09= AddWaitEventToSet(wes,=20WL_SOCKET_READABLE,=20syslogPipe[0],=20NULL,=20= NULL,=20NULL);=0A=20#endif=0A=20=0A=20=09/*=20main=20worker=20loop=20*/=0A= diff=20--git=20a/src/backend/replication/walsender.c=20= b/src/backend/replication/walsender.c=0Aindex=2066507e9c2dd..d2749a2ca67=20= 100644=0A---=20a/src/backend/replication/walsender.c=0A+++=20= b/src/backend/replication/walsender.c=0A@@=20-3846,8=20+3846,9=20@@=20= static=20void=0A=20WalSndWait(uint32=20socket_events,=20long=20timeout,=20= uint32=20wait_event)=0A=20{=0A=20=09WaitEvent=09event;=0A+=09= ConditionVariable=20*cv=20=3D=20NULL;=0A=20=0A-=09= ModifyWaitEvent(FeBeWaitSet,=20FeBeWaitSetSocketPos,=20socket_events,=20= NULL);=0A+=09ModifyWaitEvent(FeBeWaitSet,=20FeBeWaitSetSocketPos,=20= socket_events,=20NULL,=20NULL);=0A=20=0A=20=09/*=0A=20=09=20*=20We=20use=20= a=20condition=20variable=20to=20efficiently=20wake=20up=20walsenders=20= in=0A@@=20-3867,9=20+3868,6=20@@=20WalSndWait(uint32=20socket_events,=20= long=20timeout,=20uint32=20wait_event)=0A=20=09=20*=20release=20for=20= every=20iteration,=20just=20to=20wake=20up=20only=20the=20waiting=0A=20=09= =20*=20walsenders.=20It=20makes=20WalSndWakeup()=20callers'=20life=20= easy.=0A=20=09=20*=0A-=09=20*=20XXX:=20A=20desirable=20future=20= improvement=20would=20be=20to=20add=20support=20for=20CVs=0A-=09=20*=20= into=20WaitEventSetWait().=0A-=09=20*=0A=20=09=20*=20And,=20we=20use=20= separate=20shared=20memory=20CVs=20for=20physical=20and=20logical=0A=20=09= =20*=20walsenders=20for=20selective=20wake=20ups,=20see=20WalSndWakeup()=20= for=20more=20details.=0A=20=09=20*=0A@@=20-3878,20=20+3876,19=20@@=20= WalSndWait(uint32=20socket_events,=20long=20timeout,=20uint32=20= wait_event)=0A=20=09=20*=20the=20receipt=20of=20the=20LSN.=0A=20=09=20*/=0A= =20=09if=20(wait_event=20=3D=3D=20= WAIT_EVENT_WAIT_FOR_STANDBY_CONFIRMATION)=0A-=09=09= ConditionVariablePrepareToSleep(&WalSndCtl->wal_confirm_rcv_cv);=0A+=09=09= cv=20=3D=20&WalSndCtl->wal_confirm_rcv_cv;=0A=20=09else=20if=20= (MyWalSnd->kind=20=3D=3D=20REPLICATION_KIND_PHYSICAL)=0A-=09=09= ConditionVariablePrepareToSleep(&WalSndCtl->wal_flush_cv);=0A+=09=09cv=20= =3D=20&WalSndCtl->wal_flush_cv;=0A=20=09else=20if=20(MyWalSnd->kind=20=3D=3D= =20REPLICATION_KIND_LOGICAL)=0A-=09=09= ConditionVariablePrepareToSleep(&WalSndCtl->wal_replay_cv);=0A+=09=09cv=20= =3D=20&WalSndCtl->wal_replay_cv;=0A+=0A+=09ModifyWaitEvent(FeBeWaitSet,=20= FeBeWaitSetCVPos,=20WL_CONDITION_VARIABLE,=20NULL,=20cv);=0A=20=0A=20=09= if=20(WaitEventSetWait(FeBeWaitSet,=20timeout,=20&event,=201,=20= wait_event)=20=3D=3D=201=20&&=0A=20=09=09(event.events=20&=20= WL_POSTMASTER_DEATH))=0A=20=09{=0A-=09=09ConditionVariableCancelSleep();=0A= =20=09=09proc_exit(1);=0A=20=09}=0A-=0A-=09= ConditionVariableCancelSleep();=0A=20}=0A=20=0A=20/*=0Adiff=20--git=20= a/src/backend/storage/ipc/latch.c=20b/src/backend/storage/ipc/latch.c=0A= index=208537e9fef2d..9b148d0f52b=20100644=0A---=20= a/src/backend/storage/ipc/latch.c=0A+++=20= b/src/backend/storage/ipc/latch.c=0A@@=20-41,7=20+41,7=20@@=20= InitializeLatchWaitSet(void)=0A=20=09/*=20Set=20up=20the=20WaitEventSet=20= used=20by=20WaitLatch().=20*/=0A=20=09LatchWaitSet=20=3D=20= CreateWaitEventSet(NULL,=202);=0A=20=09latch_pos=20=3D=20= AddWaitEventToSet(LatchWaitSet,=20WL_LATCH_SET,=20PGINVALID_SOCKET,=0A-=09= =09=09=09=09=09=09=09=20=20MyLatch,=20NULL);=0A+=09=09=09=09=09=09=09=09=20= =20MyLatch,=20NULL,=20NULL);=0A=20=09Assert(latch_pos=20=3D=3D=20= LatchWaitSetLatchPos);=0A=20=0A=20=09/*=0A@@=20-51,7=20+51,7=20@@=20= InitializeLatchWaitSet(void)=0A=20=09if=20(IsUnderPostmaster)=0A=20=09{=0A= =20=09=09latch_pos=20=3D=20AddWaitEventToSet(LatchWaitSet,=20= WL_EXIT_ON_PM_DEATH,=0A-=09=09=09=09=09=09=09=09=09=20=20= PGINVALID_SOCKET,=20NULL,=20NULL);=0A+=09=09=09=09=09=09=09=09=09=20=20= PGINVALID_SOCKET,=20NULL,=20NULL,=20NULL);=0A=20=09=09Assert(latch_pos=20= =3D=3D=20LatchWaitSetPostmasterDeathPos);=0A=20=09}=0A=20}=0A@@=20= -186,12=20+186,12=20@@=20WaitLatch(Latch=20*latch,=20int=20wakeEvents,=20= long=20timeout,=0A=20=09=20*/=0A=20=09if=20(!(wakeEvents=20&=20= WL_LATCH_SET))=0A=20=09=09latch=20=3D=20NULL;=0A-=09= ModifyWaitEvent(LatchWaitSet,=20LatchWaitSetLatchPos,=20WL_LATCH_SET,=20= latch);=0A+=09ModifyWaitEvent(LatchWaitSet,=20LatchWaitSetLatchPos,=20= WL_LATCH_SET,=20latch,=20NULL);=0A=20=0A=20=09if=20(IsUnderPostmaster)=0A= =20=09=09ModifyWaitEvent(LatchWaitSet,=20LatchWaitSetPostmasterDeathPos,=0A= =20=09=09=09=09=09=09(wakeEvents=20&=20(WL_EXIT_ON_PM_DEATH=20|=20= WL_POSTMASTER_DEATH)),=0A-=09=09=09=09=09=09NULL);=0A+=09=09=09=09=09=09= NULL,=20NULL);=0A=20=0A=20=09if=20(WaitEventSetWait(LatchWaitSet,=0A=20=09= =09=09=09=09=09=20(wakeEvents=20&=20WL_TIMEOUT)=20?=20timeout=20:=20-1,=0A= @@=20-235,7=20+235,7=20@@=20WaitLatchOrSocket(Latch=20*latch,=20int=20= wakeEvents,=20pgsocket=20sock,=0A=20=0A=20=09if=20(wakeEvents=20&=20= WL_LATCH_SET)=0A=20=09=09AddWaitEventToSet(set,=20WL_LATCH_SET,=20= PGINVALID_SOCKET,=0A-=09=09=09=09=09=09=20=20latch,=20NULL);=0A+=09=09=09= =09=09=09=20=20latch,=20NULL,=20NULL);=0A=20=0A=20=09/*=20= Postmaster-managed=20callers=20must=20handle=20postmaster=20death=20= somehow.=20*/=0A=20=09Assert(!IsUnderPostmaster=20||=0A@@=20-244,18=20= +244,18=20@@=20WaitLatchOrSocket(Latch=20*latch,=20int=20wakeEvents,=20= pgsocket=20sock,=0A=20=0A=20=09if=20((wakeEvents=20&=20= WL_POSTMASTER_DEATH)=20&&=20IsUnderPostmaster)=0A=20=09=09= AddWaitEventToSet(set,=20WL_POSTMASTER_DEATH,=20PGINVALID_SOCKET,=0A-=09=09= =09=09=09=09=20=20NULL,=20NULL);=0A+=09=09=09=09=09=09=20=20NULL,=20= NULL,=20NULL);=0A=20=0A=20=09if=20((wakeEvents=20&=20= WL_EXIT_ON_PM_DEATH)=20&&=20IsUnderPostmaster)=0A=20=09=09= AddWaitEventToSet(set,=20WL_EXIT_ON_PM_DEATH,=20PGINVALID_SOCKET,=0A-=09=09= =09=09=09=09=20=20NULL,=20NULL);=0A+=09=09=09=09=09=09=20=20NULL,=20= NULL,=20NULL);=0A=20=0A=20=09if=20(wakeEvents=20&=20WL_SOCKET_MASK)=0A=20= =09{=0A=20=09=09int=09=09=09ev;=0A=20=0A=20=09=09ev=20=3D=20wakeEvents=20= &=20WL_SOCKET_MASK;=0A-=09=09AddWaitEventToSet(set,=20ev,=20sock,=20= NULL,=20NULL);=0A+=09=09AddWaitEventToSet(set,=20ev,=20sock,=20NULL,=20= NULL,=20NULL);=0A=20=09}=0A=20=0A=20=09rc=20=3D=20WaitEventSetWait(set,=20= timeout,=20&event,=201,=20wait_event_info);=0Adiff=20--git=20= a/src/backend/storage/ipc/waiteventset.c=20= b/src/backend/storage/ipc/waiteventset.c=0Aindex=20= 0f228e1e7b8..2382e0cae2a=20100644=0A---=20= a/src/backend/storage/ipc/waiteventset.c=0A+++=20= b/src/backend/storage/ipc/waiteventset.c=0A@@=20-73,6=20+73,7=20@@=0A=20= #include=20"storage/fd.h"=0A=20#include=20"storage/ipc.h"=0A=20#include=20= "storage/pmsignal.h"=0A+#include=20"storage/condition_variable.h"=0A=20= #include=20"storage/latch.h"=0A=20#include=20"storage/waiteventset.h"=0A=20= #include=20"utils/memutils.h"=0A@@=20-137,6=20+138,15=20@@=20struct=20= WaitEventSet=0A=20=09Latch=09=20=20=20*latch;=0A=20=09int=09=09=09= latch_pos;=0A=20=0A+=09/*=0A+=09=20*=20If=20WL_CONDITION_VARIABLE=20is=20= specified=20in=20any=20wait=20event,=20cv=20is=20a=0A+=09=20*=20pointer=20= to=20said=20condition=20variable,=20and=20cv_pos=20the=20offset=20in=20= the=0A+=09=20*=20->events=20array.=0A+=09=20*/=0A+=09ConditionVariable=20= *cv;=0A+=09int=09=09=09cv_pos;=0A+=09bool=09=09cv_maybe_signaled;=09/*=20= Decide=20if=20check=20signaled=20after=20poll=20*/=0A+=0A=20=09/*=0A=20=09= =20*=20WL_EXIT_ON_PM_DEATH=20is=20converted=20to=20WL_POSTMASTER_DEATH,=20= but=20this=20flag=0A=20=09=20*=20is=20set=20so=20that=20we'll=20exit=20= immediately=20if=20postmaster=20death=20is=20detected,=0A@@=20-414,6=20= +424,8=20@@=20CreateWaitEventSet(ResourceOwner=20resowner,=20int=20= nevents)=0A=20#endif=0A=20=0A=20=09set->latch=20=3D=20NULL;=0A+=09= set->cv=20=3D=20NULL;=0A+=09set->cv_maybe_signaled=20=3D=20false;=0A=20=09= set->nevents_space=20=3D=20nevents;=0A=20=09= set->exit_on_postmaster_death=20=3D=20false;=0A=20=0A@@=20-550,6=20= +562,7=20@@=20FreeWaitEventSetAfterFork(WaitEventSet=20*set)=0A=20=20*=09= =20platforms,=20this=20is=20the=20same=20as=20WL_SOCKET_READABLE)=0A=20=20= *=20-=20WL_SOCKET_CLOSED:=20Wait=20for=20socket=20to=20be=20closed=20by=20= remote=20peer.=0A=20=20*=20-=20WL_EXIT_ON_PM_DEATH:=20Exit=20immediately=20= if=20the=20postmaster=20dies=0A+=20*=20-=20WL_CONDITION_VARIABLE:=20Wait=20= for=20a=20condition=20variable=20to=20be=20signaled.=0A=20=20*=0A=20=20*=20= Returns=20the=20offset=20in=20WaitEventSet->events=20(starting=20from=20= 0),=20which=20can=20be=0A=20=20*=20used=20to=20modify=20previously=20= added=20wait=20events=20using=20ModifyWaitEvent().=0A@@=20-568,7=20= +581,7=20@@=20FreeWaitEventSetAfterFork(WaitEventSet=20*set)=0A=20=20*/=0A= =20int=0A=20AddWaitEventToSet(WaitEventSet=20*set,=20uint32=20events,=20= pgsocket=20fd,=20Latch=20*latch,=0A-=09=09=09=09=20=20void=20*user_data)=0A= +=09=09=09=09=20=20ConditionVariable=20*cv,=20void=20*user_data)=0A=20{=0A= =20=09WaitEvent=20=20*event;=0A=20=0A@@=20-596,6=20+609,18=20@@=20= AddWaitEventToSet(WaitEventSet=20*set,=20uint32=20events,=20pgsocket=20= fd,=20Latch=20*latch,=0A=20=09=09=09elog(ERROR,=20"cannot=20wait=20on=20= latch=20without=20a=20specified=20latch");=0A=20=09}=0A=20=0A+=09/*=0A+=09= =20*=20When=20add=20a=20CV=20event,=20we=20allow=20a=20NULL=20cv,=20= because=20it=20can=20be=20set=20later=0A+=09=20*=20with=20= ModifyWaitEvent.=0A+=09=20*/=0A+=09if=20(cv)=0A+=09{=0A+=09=09if=20= (set->cv)=0A+=09=09=09elog(ERROR,=20"cannot=20wait=20on=20more=20than=20= one=20condition=20variable");=0A+=09=09if=20((events=20&=20= WL_CONDITION_VARIABLE)=20!=3D=20WL_CONDITION_VARIABLE)=0A+=09=09=09= elog(ERROR,=20"condition=20variable=20events=20only=20support=20being=20= set");=0A+=09}=0A+=0A=20=09/*=20waiting=20for=20socket=20readiness=20= without=20a=20socket=20indicates=20a=20bug=20*/=0A=20=09if=20(fd=20=3D=3D=20= PGINVALID_SOCKET=20&&=20(events=20&=20WL_SOCKET_MASK))=0A=20=09=09= elog(ERROR,=20"cannot=20wait=20on=20socket=20event=20without=20a=20= socket");=0A@@=20-624,6=20+649,13=20@@=20AddWaitEventToSet(WaitEventSet=20= *set,=20uint32=20events,=20pgsocket=20fd,=20Latch=20*latch,=0A=20#endif=0A= =20#endif=0A=20=09}=0A+=09else=20if=20(events=20=3D=3D=20= WL_CONDITION_VARIABLE)=0A+=09{=0A+=09=09set->cv=20=3D=20cv;=0A+=09=09= set->cv_pos=20=3D=20event->pos;=0A+=09=09event->fd=20=3D=20= PGINVALID_SOCKET;=0A+=09=09return=20event->pos;=0A+=09}=0A=20=09else=20= if=20(events=20=3D=3D=20WL_POSTMASTER_DEATH)=0A=20=09{=0A=20#ifndef=20= WIN32=0A@@=20-653,14=20+685,15=20@@=20AddWaitEventToSet(WaitEventSet=20= *set,=20uint32=20events,=20pgsocket=20fd,=20Latch=20*latch,=0A=20=20*=20= 'pos'=20is=20the=20id=20returned=20by=20AddWaitEventToSet.=0A=20=20*/=0A=20= void=0A-ModifyWaitEvent(WaitEventSet=20*set,=20int=20pos,=20uint32=20= events,=20Latch=20*latch)=0A+ModifyWaitEvent(WaitEventSet=20*set,=20int=20= pos,=20uint32=20events,=20Latch=20*latch,=0A+=09=09=09=09= ConditionVariable=20*cv)=0A=20{=0A=20=09WaitEvent=20=20*event;=0A=20#if=20= defined(WAIT_USE_KQUEUE)=0A=20=09int=09=09=09old_events;=0A=20#endif=0A=20= =0A-=09Assert(pos=20<=20set->nevents);=0A+=09Assert(pos=20>=3D=200=20&&=20= pos=20<=20set->nevents);=0A=20=0A=20=09event=20=3D=20&set->events[pos];=0A= =20#if=20defined(WAIT_USE_KQUEUE)=0A@@=20-682,6=20+715,21=20@@=20= ModifyWaitEvent(WaitEventSet=20*set,=20int=20pos,=20uint32=20events,=20= Latch=20*latch)=0A=20=09=09return;=0A=20=09}=0A=20=0A+=09/*=0A+=09=20*=20= Change=20the=20condition=20variable=20associated=20with=20the=20event.=20= =20As=20CV=20doesn't=0A+=09=20*=20rely=20on=20kernal,=20go=20ahead=20= with=20a=20fast-path=20and=20only=20update=20the=20CV=0A+=09=20*=20= pointer.=0A+=09=20*/=0A+=09if=20(event->events=20=3D=3D=20= WL_CONDITION_VARIABLE)=0A+=09{=0A+=09=09if=20(events=20!=3D=20= WL_CONDITION_VARIABLE)=0A+=09=09=09elog(ERROR,=20"cannot=20change=20= event=20type=20of=20a=20condition=20variable=20event");=0A+=09=09if=20= (cv=20=3D=3D=20NULL)=0A+=09=09=09elog(ERROR,=20"cannot=20set=20condition=20= variable=20to=20NULL");=0A+=09=09set->cv=20=3D=20cv;=0A+=09=09return;=0A= +=09}=0A+=0A=20=09/*=0A=20=09=20*=20If=20neither=20the=20event=20mask=20= nor=20the=20associated=20latch=20changes,=20return=0A=20=09=20*=20early.=20= That's=20an=20important=20optimization=20for=20some=20sockets,=20where=0A= @@=20-1042,9=20+1090,11=20@@=20WaitEventSetWait(WaitEventSet=20*set,=20= long=20timeout,=0A=20=09=09=09=09=20uint32=20wait_event_info)=0A=20{=0A=20= =09int=09=09=09returned_events=20=3D=200;=0A+=09WaitEvent=20=20= *first_occurred_event=20=3D=20occurred_events;=0A=20=09instr_time=09= start_time;=0A=20=09instr_time=09cur_time;=0A=20=09long=09=09cur_timeout=20= =3D=20-1;=0A+=09bool=09=09cv_signaled=20=3D=20false;=0A=20=0A=20=09= Assert(nevents=20>=200);=0A=20=0A@@=20-1061,6=20+1111,9=20@@=20= WaitEventSetWait(WaitEventSet=20*set,=20long=20timeout,=0A=20=09else=0A=20= =09=09INSTR_TIME_SET_ZERO(start_time);=0A=20=0A+=09if=20(set->cv=20!=3D=20= NULL)=0A+=09=09ConditionVariablePrepareToSleep(set->cv);=0A+=0A=20=09= pgstat_report_wait_start(wait_event_info);=0A=20=0A=20#ifndef=20WIN32=0A= @@=20-1072,6=20+1125,7=20@@=20WaitEventSetWait(WaitEventSet=20*set,=20= long=20timeout,=0A=20=09while=20(returned_events=20=3D=3D=200)=0A=20=09{=0A= =20=09=09int=09=09=09rc;=0A+=09=09WaitEvent=20=20*block_occurred_events=20= =3D=20occurred_events;=0A=20=0A=20=09=09/*=0A=20=09=09=20*=20Check=20if=20= the=20latch=20is=20set=20already=20first.=20=20If=20so,=20we=20either=20= exit=0A@@=20-1115,6=20+1169,7=20@@=20WaitEventSetWait(WaitEventSet=20= *set,=20long=20timeout,=0A=20=09=09=09occurred_events->user_data=20=3D=0A= =20=09=09=09=09set->events[set->latch_pos].user_data;=0A=20=09=09=09= occurred_events->events=20=3D=20WL_LATCH_SET;=0A+=0A=20=09=09=09= occurred_events++;=0A=20=09=09=09returned_events++;=0A=20=0A@@=20-1133,6=20= +1188,38=20@@=20WaitEventSetWait(WaitEventSet=20*set,=20long=20timeout,=0A= =20=09=09=09timeout=20=3D=200;=0A=20=09=09}=0A=20=0A+=09=09if=20= (set->cv)=0A+=09=09=09cv_signaled=20=3D=20= ConditionVariableSignaled(set->cv);=0A+=0A+=09=09if=20(set->cv=20&&=20= !cv_signaled)=0A+=09=09=09set->cv_maybe_signaled=20=3D=20true;=0A+=0A+=09= =09if=20(set->cv=20&&=20cv_signaled)=0A+=09=09{=0A+=09=09=09= occurred_events->fd=20=3D=20PGINVALID_SOCKET;=0A+=09=09=09= occurred_events->pos=20=3D=20set->cv_pos;=0A+=09=09=09= occurred_events->user_data=20=3D=0A+=09=09=09=09= set->events[set->cv_pos].user_data;=0A+=09=09=09occurred_events->events=20= =3D=20WL_CONDITION_VARIABLE;=0A+=0A+=09=09=09occurred_events++;=0A+=09=09= =09returned_events++;=0A+=0A+=09=09=09/*=20could=20have=20been=20set=20= above=20*/=0A+=09=09=09set->cv_maybe_signaled=20=3D=20false;=0A+=0A+=09=09= =09if=20(returned_events=20=3D=3D=20nevents)=0A+=09=09=09=09break;=09=09=09= /*=20output=20buffer=20full=20already=20*/=0A+=0A+=09=09=09/*=0A+=09=09=09= =20*=20Even=20though=20we=20already=20have=20an=20event,=20we'll=20poll=20= just=20once=20with=0A+=09=09=09=20*=20zero=20timeout=20to=20see=20what=20= non-latch=20events=20we=20can=20fit=20into=20the=0A+=09=09=09=20*=20= output=20buffer=20at=20the=20same=20time.=0A+=09=09=09=20*/=0A+=09=09=09= cur_timeout=20=3D=200;=0A+=09=09=09timeout=20=3D=200;=0A+=09=09}=0A+=0A=20= =09=09/*=0A=20=09=09=20*=20Wait=20for=20events=20using=20the=20readiness=20= primitive=20chosen=20at=20the=20top=20of=0A=20=09=09=20*=20this=20file.=20= If=20-1=20is=20returned,=20a=20timeout=20has=20occurred,=20if=200=20we=20= have=0A@@=20-1145,6=20+1232,25=20@@=20WaitEventSetWait(WaitEventSet=20= *set,=20long=20timeout,=0A=20=09=09=09set->latch->maybe_sleeping)=0A=20=09= =09=09set->latch->maybe_sleeping=20=3D=20false;=0A=20=0A+=09=09/*=20= Check=20CV=20again=20after=20waiting=20if=20not=20done=20before=20= waiting=20*/=0A+=09=09if=20(set->cv=20&&=20set->cv_maybe_signaled=20&&=20= ConditionVariableSignaled(set->cv))=0A+=09=09{=0A+=09=09=09= occurred_events->fd=20=3D=20PGINVALID_SOCKET;=0A+=09=09=09= occurred_events->pos=20=3D=20set->cv_pos;=0A+=09=09=09= occurred_events->user_data=20=3D=0A+=09=09=09=09= set->events[set->cv_pos].user_data;=0A+=09=09=09occurred_events->events=20= =3D=20WL_CONDITION_VARIABLE;=0A+=0A+=09=09=09occurred_events++;=0A+=09=09= =09returned_events++;=0A+=0A+=09=09=09if=20(returned_events=20=3D=3D=20= nevents)=0A+=09=09=09=09break;=09=09=09/*=20output=20buffer=20full=20= already=20*/=0A+=09=09}=0A+=0A+=09=09if=20(set->cv=20&&=20= set->cv_maybe_signaled)=0A+=09=09=09set->cv_maybe_signaled=20=3D=20= false;=0A+=0A=20=09=09if=20(rc=20=3D=3D=20-1)=0A=20=09=09=09break;=09=09=09= =09/*=20timeout=20occurred=20*/=0A=20=09=09else=0A@@=20-1166,10=20= +1272,12=20@@=20WaitEventSetWait(WaitEventSet=20*set,=20long=20timeout,=0A= =20=0A=20=09pgstat_report_wait_end();=0A=20=0A+=09if=20(set->cv=20!=3D=20= NULL)=0A+=09=09ConditionVariableCancelSleep();=0A+=0A=20=09return=20= returned_events;=0A=20}=0A=20=0A-=0A=20#if=20defined(WAIT_USE_EPOLL)=0A=20= =0A=20/*=0Adiff=20--git=20= a/src/backend/storage/lmgr/condition_variable.c=20= b/src/backend/storage/lmgr/condition_variable.c=0Aindex=20= 1f16b3f7475..c04bc420bcf=20100644=0A---=20= a/src/backend/storage/lmgr/condition_variable.c=0A+++=20= b/src/backend/storage/lmgr/condition_variable.c=0A@@=20-182,13=20+182,7=20= @@=20ConditionVariableTimedSleep(ConditionVariable=20*cv,=20long=20= timeout,=0A=20=09=09=20*=20by=20something=20other=20than=20= ConditionVariableSignal;=20though=20we=20don't=0A=20=09=09=20*=20= guarantee=20not=20to=20return=20spuriously,=20we'll=20avoid=20this=20= obvious=20case.=0A=20=09=09=20*/=0A-=09=09SpinLockAcquire(&cv->mutex);=0A= -=09=09if=20(!proclist_contains(&cv->wakeup,=20MyProcNumber,=20= cvWaitLink))=0A-=09=09{=0A-=09=09=09done=20=3D=20true;=0A-=09=09=09= proclist_push_tail(&cv->wakeup,=20MyProcNumber,=20cvWaitLink);=0A-=09=09= }=0A-=09=09SpinLockRelease(&cv->mutex);=0A+=09=09done=20=3D=20= ConditionVariableSignaled(cv);=0A=20=0A=20=09=09/*=0A=20=09=09=20*=20= Check=20for=20interrupts,=20and=20return=20spuriously=20if=20that=20= caused=20the=0A@@=20-217,6=20+211,31=20@@=20= ConditionVariableTimedSleep(ConditionVariable=20*cv,=20long=20timeout,=0A= =20=09}=0A=20}=0A=20=0A+/*=0A+=20*=20Check=20whether=20this=20process=20= was=20removed=20from=20cv's=20wait=20list=20by=20a=20CV=0A+=20*=20= signal/broadcast.=20If=20so,=20re-add=20it=20to=20preserve=20wakeups=20= while=20the=20caller=0A+=20*=20checks=20the=20predicate.=0A+=20*/=0A= +bool=0A+ConditionVariableSignaled(ConditionVariable=20*cv)=0A+{=0A+=09= bool=09=09signaled=20=3D=20false;=0A+=0A+=09/*=20Ignore=20probes=20for=20= CVs=20we=20are=20not=20currently=20prepared=20to=20sleep=20on.=20*/=0A+=09= if=20(cv_sleep_target=20!=3D=20cv)=0A+=09=09return=20false;=0A+=0A+=09= SpinLockAcquire(&cv->mutex);=0A+=09if=20(!proclist_contains(&cv->wakeup,=20= MyProcNumber,=20cvWaitLink))=0A+=09{=0A+=09=09signaled=20=3D=20true;=0A+=09= =09proclist_push_tail(&cv->wakeup,=20MyProcNumber,=20cvWaitLink);=0A+=09= }=0A+=09SpinLockRelease(&cv->mutex);=0A+=0A+=09return=20signaled;=0A+}=0A= +=0A=20/*=0A=20=20*=20Cancel=20any=20pending=20sleep=20operation.=0A=20=20= *=0Adiff=20--git=20a/src/backend/utils/init/miscinit.c=20= b/src/backend/utils/init/miscinit.c=0Aindex=20ba191977697..b970c1d727c=20= 100644=0A---=20a/src/backend/utils/init/miscinit.c=0A+++=20= b/src/backend/utils/init/miscinit.c=0A@@=20-222,7=20+222,7=20@@=20= SwitchToSharedLatch(void)=0A=20=0A=20=09if=20(FeBeWaitSet)=0A=20=09=09= ModifyWaitEvent(FeBeWaitSet,=20FeBeWaitSetLatchPos,=20WL_LATCH_SET,=0A-=09= =09=09=09=09=09MyLatch);=0A+=09=09=09=09=09=09MyLatch,=20NULL);=0A=20=0A=20= =09/*=0A=20=09=20*=20Set=20the=20shared=20latch=20as=20the=20local=20one=20= might=20have=20been=20set.=20This=0A@@=20-249,7=20+249,7=20@@=20= SwitchBackToLocalLatch(void)=0A=20=0A=20=09if=20(FeBeWaitSet)=0A=20=09=09= ModifyWaitEvent(FeBeWaitSet,=20FeBeWaitSetLatchPos,=20WL_LATCH_SET,=0A-=09= =09=09=09=09=09MyLatch);=0A+=09=09=09=09=09=09MyLatch,=20NULL);=0A=20=0A=20= =09SetLatch(MyLatch);=0A=20}=0Adiff=20--git=20= a/src/include/libpq/libpq.h=20b/src/include/libpq/libpq.h=0Aindex=20= c9b934d2321..8d13eaf8393=20100644=0A---=20a/src/include/libpq/libpq.h=0A= +++=20b/src/include/libpq/libpq.h=0A@@=20-65,7=20+65,8=20@@=20extern=20= PGDLLIMPORT=20WaitEventSet=20*FeBeWaitSet;=0A=20=0A=20#define=20= FeBeWaitSetSocketPos=200=0A=20#define=20FeBeWaitSetLatchPos=201=0A= -#define=20FeBeWaitSetNEvents=203=0A+#define=20FeBeWaitSetCVPos=202=0A= +#define=20FeBeWaitSetNEvents=204=0A=20=0A=20extern=20int=09= ListenServerPort(int=20family,=20const=20char=20*hostName,=0A=20=09=09=09= =09=09=09=09=20unsigned=20short=20portNumber,=20const=20char=20= *unixSocketDir,=0Adiff=20--git=20= a/src/include/storage/condition_variable.h=20= b/src/include/storage/condition_variable.h=0Aindex=20= 14bd6dd55c0..fb7e4bb67f2=20100644=0A---=20= a/src/include/storage/condition_variable.h=0A+++=20= b/src/include/storage/condition_variable.h=0A@@=20-57,6=20+57,7=20@@=20= extern=20void=20ConditionVariableSleep(ConditionVariable=20*cv,=20uint32=20= wait_event_info=0A=20extern=20bool=20= ConditionVariableTimedSleep(ConditionVariable=20*cv,=20long=20timeout,=0A= =20=09=09=09=09=09=09=09=09=09=09uint32=20wait_event_info);=0A=20extern=20= bool=20ConditionVariableCancelSleep(void);=0A+extern=20bool=20= ConditionVariableSignaled(ConditionVariable=20*cv);=0A=20=0A=20/*=0A=20=20= *=20Optionally,=20ConditionVariablePrepareToSleep=20can=20be=20called=20= before=20entering=0Adiff=20--git=20a/src/include/storage/waiteventset.h=20= b/src/include/storage/waiteventset.h=0Aindex=205341267f0a0..f3d569a6aa0=20= 100644=0A---=20a/src/include/storage/waiteventset.h=0A+++=20= b/src/include/storage/waiteventset.h=0A@@=20-25,6=20+25,7=20@@=0A=20= #ifndef=20WAITEVENTSET_H=0A=20#define=20WAITEVENTSET_H=0A=20=0A+#include=20= "storage/condition_variable.h"=0A=20#include=20"utils/resowner.h"=0A=20=0A= =20/*=0A@@=20-50,6=20+51,7=20@@=0A=20/*=20avoid=20having=20to=20deal=20= with=20case=20on=20platforms=20not=20requiring=20it=20*/=0A=20#define=20= WL_SOCKET_ACCEPT=09WL_SOCKET_READABLE=0A=20#endif=0A+#define=20= WL_CONDITION_VARIABLE=20(1=20<<=209)=0A=20#define=20WL_SOCKET_MASK=09=09= (WL_SOCKET_READABLE=20|=20\=0A=20=09=09=09=09=09=09=09=20= WL_SOCKET_WRITEABLE=20|=20\=0A=20=09=09=09=09=09=09=09=20= WL_SOCKET_CONNECTED=20|=20\=0A@@=20-81,9=20+83,10=20@@=20extern=20= WaitEventSet=20*CreateWaitEventSet(ResourceOwner=20resowner,=20int=20= nevents);=0A=20extern=20void=20FreeWaitEventSet(WaitEventSet=20*set);=0A=20= extern=20void=20FreeWaitEventSetAfterFork(WaitEventSet=20*set);=0A=20= extern=20int=09AddWaitEventToSet(WaitEventSet=20*set,=20uint32=20events,=20= pgsocket=20fd,=0A-=09=09=09=09=09=09=09=20=20struct=20Latch=20*latch,=20= void=20*user_data);=0A+=09=09=09=09=09=09=09=20=20struct=20Latch=20= *latch,=20ConditionVariable=20*cv,=0A+=09=09=09=09=09=09=09=20=20void=20= *user_data);=0A=20extern=20void=20ModifyWaitEvent(WaitEventSet=20*set,=20= int=20pos,=20uint32=20events,=0A-=09=09=09=09=09=09=09struct=20Latch=20= *latch);=0A+=09=09=09=09=09=09=09struct=20Latch=20*latch,=20= ConditionVariable=20*cv);=0A=20extern=20int=09= WaitEventSetWait(WaitEventSet=20*set,=20long=20timeout,=0A=20=09=09=09=09= =09=09=09=20WaitEvent=20*occurred_events,=20int=20nevents,=0A=20=09=09=09= =09=09=09=09=20uint32=20wait_event_info);=0A--=20=0A2.50.1=20(Apple=20= Git-155)=0A=0A= --Apple-Mail=_4A17D358-3B20-427B-9DDC-057D3AC4DFDC--