]> granicus.if.org Git - postgresql/blob - src/backend/port/win32_latch.c
Attempt to fix some issues in our Windows socket code.
[postgresql] / src / backend / port / win32_latch.c
1 /*-------------------------------------------------------------------------
2  *
3  * win32_latch.c
4  *        Routines for inter-process latches
5  *
6  * See unix_latch.c for header comments for the exported functions;
7  * the API presented here is supposed to be the same as there.
8  *
9  * The Windows implementation uses Windows events that are inherited by
10  * all postmaster child processes.
11  *
12  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  * IDENTIFICATION
16  *        src/backend/port/win32_latch.c
17  *
18  *-------------------------------------------------------------------------
19  */
20 #include "postgres.h"
21
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <unistd.h>
25
26 #include "miscadmin.h"
27 #include "postmaster/postmaster.h"
28 #include "storage/latch.h"
29 #include "storage/pmsignal.h"
30 #include "storage/shmem.h"
31
32
33 void
34 InitLatch(volatile Latch *latch)
35 {
36         latch->is_set = false;
37         latch->owner_pid = MyProcPid;
38         latch->is_shared = false;
39
40         latch->event = CreateEvent(NULL, TRUE, FALSE, NULL);
41         if (latch->event == NULL)
42                 elog(ERROR, "CreateEvent failed: error code %lu", GetLastError());
43 }
44
45 void
46 InitSharedLatch(volatile Latch *latch)
47 {
48         SECURITY_ATTRIBUTES sa;
49
50         latch->is_set = false;
51         latch->owner_pid = 0;
52         latch->is_shared = true;
53
54         /*
55          * Set up security attributes to specify that the events are inherited.
56          */
57         ZeroMemory(&sa, sizeof(sa));
58         sa.nLength = sizeof(sa);
59         sa.bInheritHandle = TRUE;
60
61         latch->event = CreateEvent(&sa, TRUE, FALSE, NULL);
62         if (latch->event == NULL)
63                 elog(ERROR, "CreateEvent failed: error code %lu", GetLastError());
64 }
65
66 void
67 OwnLatch(volatile Latch *latch)
68 {
69         /* Sanity checks */
70         Assert(latch->is_shared);
71         if (latch->owner_pid != 0)
72                 elog(ERROR, "latch already owned");
73
74         latch->owner_pid = MyProcPid;
75 }
76
77 void
78 DisownLatch(volatile Latch *latch)
79 {
80         Assert(latch->is_shared);
81         Assert(latch->owner_pid == MyProcPid);
82
83         latch->owner_pid = 0;
84 }
85
86 int
87 WaitLatch(volatile Latch *latch, int wakeEvents, long timeout)
88 {
89         return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout);
90 }
91
92 int
93 WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
94                                   long timeout)
95 {
96         DWORD           rc;
97         HANDLE          events[4];
98         HANDLE          latchevent;
99         HANDLE          sockevent = WSA_INVALID_EVENT;
100         int                     numevents;
101         int                     result = 0;
102         int                     pmdeath_eventno = 0;
103
104         /* Ignore WL_SOCKET_* events if no valid socket is given */
105         if (sock == PGINVALID_SOCKET)
106                 wakeEvents &= ~(WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE);
107
108         Assert(wakeEvents != 0);        /* must have at least one wake event */
109
110         if ((wakeEvents & WL_LATCH_SET) && latch->owner_pid != MyProcPid)
111                 elog(ERROR, "cannot wait on a latch owned by another process");
112
113         /* Convert timeout to form used by WaitForMultipleObjects() */
114         if (wakeEvents & WL_TIMEOUT)
115                 Assert(timeout >= 0);
116         else
117                 timeout = INFINITE;
118
119         /*
120          * Construct an array of event handles for WaitforMultipleObjects().
121          *
122          * Note: pgwin32_signal_event should be first to ensure that it will be
123          * reported when multiple events are set.  We want to guarantee that
124          * pending signals are serviced.
125          */
126         latchevent = latch->event;
127
128         events[0] = pgwin32_signal_event;
129         events[1] = latchevent;
130         numevents = 2;
131         if (wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE))
132         {
133                 /* Need an event object to represent events on the socket */
134                 int                     flags = 0;
135
136                 if (wakeEvents & WL_SOCKET_READABLE)
137                         flags |= (FD_READ | FD_CLOSE);
138                 if (wakeEvents & WL_SOCKET_WRITEABLE)
139                         flags |= FD_WRITE;
140
141                 sockevent = WSACreateEvent();
142                 if (sockevent == WSA_INVALID_EVENT)
143                         elog(ERROR, "failed to create event for socket: error code %u",
144                                  WSAGetLastError());
145                 if (WSAEventSelect(sock, sockevent, flags) != 0)
146                         elog(ERROR, "failed to set up event for socket: error code %u",
147                                  WSAGetLastError());
148
149                 events[numevents++] = sockevent;
150         }
151         if (wakeEvents & WL_POSTMASTER_DEATH)
152         {
153                 pmdeath_eventno = numevents;
154                 events[numevents++] = PostmasterHandle;
155         }
156
157         /* Ensure that signals are serviced even if latch is already set */
158         pgwin32_dispatch_queued_signals();
159
160         do
161         {
162                 /*
163                  * Reset the event, and check if the latch is set already. If someone
164                  * sets the latch between this and the WaitForMultipleObjects() call
165                  * below, the setter will set the event and WaitForMultipleObjects()
166                  * will return immediately.
167                  */
168                 if (!ResetEvent(latchevent))
169                         elog(ERROR, "ResetEvent failed: error code %lu", GetLastError());
170
171                 if ((wakeEvents & WL_LATCH_SET) && latch->is_set)
172                 {
173                         result |= WL_LATCH_SET;
174                         /*
175                          * Leave loop immediately, avoid blocking again. We don't attempt
176                          * to report any other events that might also be satisfied.
177                          */
178                         break;
179                 }
180
181                 rc = WaitForMultipleObjects(numevents, events, FALSE, timeout);
182
183                 if (rc == WAIT_FAILED)
184                         elog(ERROR, "WaitForMultipleObjects() failed: error code %lu",
185                                  GetLastError());
186                 else if (rc == WAIT_TIMEOUT)
187                 {
188                         result |= WL_TIMEOUT;
189                 }
190                 else if (rc == WAIT_OBJECT_0)
191                 {
192                         /* Service newly-arrived signals */
193                         pgwin32_dispatch_queued_signals();
194                 }
195                 else if (rc == WAIT_OBJECT_0 + 1)
196                 {
197                         /* Latch is set, we'll handle that on next iteration of loop */
198                 }
199                 else if ((wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) &&
200                                  rc == WAIT_OBJECT_0 + 2)       /* socket is at event slot 2 */
201                 {
202                         WSANETWORKEVENTS resEvents;
203
204                         ZeroMemory(&resEvents, sizeof(resEvents));
205                         if (WSAEnumNetworkEvents(sock, sockevent, &resEvents) != 0)
206                                 elog(ERROR, "failed to enumerate network events: error code %u",
207                                          WSAGetLastError());
208                         if ((wakeEvents & WL_SOCKET_READABLE) &&
209                                 (resEvents.lNetworkEvents & (FD_READ | FD_CLOSE)))
210                         {
211                                 result |= WL_SOCKET_READABLE;
212                         }
213                         if ((wakeEvents & WL_SOCKET_WRITEABLE) &&
214                                 (resEvents.lNetworkEvents & FD_WRITE))
215                         {
216                                 result |= WL_SOCKET_WRITEABLE;
217                         }
218                 }
219                 else if ((wakeEvents & WL_POSTMASTER_DEATH) &&
220                                  rc == WAIT_OBJECT_0 + pmdeath_eventno)
221                 {
222                         /*
223                          * Postmaster apparently died.  Since the consequences of falsely
224                          * returning WL_POSTMASTER_DEATH could be pretty unpleasant, we
225                          * take the trouble to positively verify this with
226                          * PostmasterIsAlive(), even though there is no known reason to
227                          * think that the event could be falsely set on Windows.
228                          */
229                         if (!PostmasterIsAlive())
230                                 result |= WL_POSTMASTER_DEATH;
231                 }
232                 else
233                         elog(ERROR, "unexpected return code from WaitForMultipleObjects(): %lu", rc);
234         }
235         while (result == 0);
236
237         /* Clean up the event object we created for the socket */
238         if (sockevent != WSA_INVALID_EVENT)
239         {
240                 WSAEventSelect(sock, NULL, 0);
241                 WSACloseEvent(sockevent);
242         }
243
244         return result;
245 }
246
247 void
248 SetLatch(volatile Latch *latch)
249 {
250         HANDLE          handle;
251
252         /* Quick exit if already set */
253         if (latch->is_set)
254                 return;
255
256         latch->is_set = true;
257
258         /*
259          * See if anyone's waiting for the latch. It can be the current process if
260          * we're in a signal handler.
261          *
262          * Use a local variable here just in case somebody changes the event field
263          * concurrently (which really should not happen).
264          */
265         handle = latch->event;
266         if (handle)
267         {
268                 SetEvent(handle);
269
270                 /*
271                  * Note that we silently ignore any errors. We might be in a signal
272                  * handler or other critical path where it's not safe to call elog().
273                  */
274         }
275 }
276
277 void
278 ResetLatch(volatile Latch *latch)
279 {
280         /* Only the owner should reset the latch */
281         Assert(latch->owner_pid == MyProcPid);
282
283         latch->is_set = false;
284 }