Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf5989b3

Browse files
committed
Avoid "could not reattach" by providing space for concurrent allocation.
We've long had reports of intermittent "could not reattach to sharedmemory" errors on Windows. Buildfarm member dory fails that way whenPGSharedMemoryReAttach() execution overlaps with creation of a threadfor the process's "default thread pool". Fix that by providing a secondregion to receive asynchronous allocations that would otherwise intrudeinto UsedShmemSegAddr. In pgwin32_ReserveSharedMemoryRegion(), stoptrying to free reservations landing at incorrect addresses; the caller'snext step has been to terminate the affected process. Back-patch to 9.4(all supported versions).Reviewed by Tom Lane. He also did much of the prerequisite research;see commitbcbf234.Discussion:https://postgr.es/m/20190402135442.GA1173872@rfd.leadboat.com
1 parent051c71c commitf5989b3

File tree

3 files changed

+86
-14
lines changed

3 files changed

+86
-14
lines changed

‎src/backend/port/win32_shmem.c

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,28 @@
1717
#include"storage/ipc.h"
1818
#include"storage/pg_shmem.h"
1919

20+
/*
21+
* Early in a process's life, Windows asynchronously creates threads for the
22+
* process's "default thread pool"
23+
* (https://docs.microsoft.com/en-us/windows/desktop/ProcThread/thread-pools).
24+
* Occasionally, thread creation allocates a stack after
25+
* PGSharedMemoryReAttach() has released UsedShmemSegAddr and before it has
26+
* mapped shared memory at UsedShmemSegAddr. This would cause mapping to fail
27+
* if the allocator preferred the just-released region for allocating the new
28+
* thread stack. We observed such failures in some Windows Server 2016
29+
* configurations. To give the system another region to prefer, reserve and
30+
* release an additional, protective region immediately before reserving or
31+
* releasing shared memory. The idea is that, if the allocator handed out
32+
* REGION1 pages before REGION2 pages at one occasion, it will do so whenever
33+
* both regions are free. Windows Server 2016 exhibits that behavior, and a
34+
* system behaving differently would have less need to protect
35+
* UsedShmemSegAddr. The protective region must be at least large enough for
36+
* one thread stack. However, ten times as much is less than 2% of the 32-bit
37+
* address space and is negligible relative to the 64-bit address space.
38+
*/
39+
#definePROTECTIVE_REGION_SIZE (10 * WIN32_STACK_RLIMIT)
40+
void*ShmemProtectiveRegion=NULL;
41+
2042
HANDLEUsedShmemSegID=INVALID_HANDLE_VALUE;
2143
void*UsedShmemSegAddr=NULL;
2244
staticSizeUsedShmemSegSize=0;
@@ -133,6 +155,12 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port,
133155
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
134156
errmsg("huge pages not supported on this platform")));
135157

158+
ShmemProtectiveRegion=VirtualAlloc(NULL,PROTECTIVE_REGION_SIZE,
159+
MEM_RESERVE,PAGE_NOACCESS);
160+
if (ShmemProtectiveRegion==NULL)
161+
elog(FATAL,"could not reserve memory region: error code %lu",
162+
GetLastError());
163+
136164
/* Room for a header? */
137165
Assert(size>MAXALIGN(sizeof(PGShmemHeader)));
138166

@@ -263,22 +291,26 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port,
263291
* an already existing shared memory segment, using the handle inherited from
264292
* the postmaster.
265293
*
266-
* UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this
267-
* routine. The caller must have already restored them to the postmaster's
268-
* values.
294+
*ShmemProtectiveRegion,UsedShmemSegID and UsedShmemSegAddr are implicit
295+
*parameters to thisroutine. The caller must have already restored them to
296+
*the postmaster'svalues.
269297
*/
270298
void
271299
PGSharedMemoryReAttach(void)
272300
{
273301
PGShmemHeader*hdr;
274302
void*origUsedShmemSegAddr=UsedShmemSegAddr;
275303

304+
Assert(ShmemProtectiveRegion!=NULL);
276305
Assert(UsedShmemSegAddr!=NULL);
277306
Assert(IsUnderPostmaster);
278307

279308
/*
280-
* Release memory regionreservation that was made by the postmaster
309+
* Release memory regionreservations made by the postmaster
281310
*/
311+
if (VirtualFree(ShmemProtectiveRegion,0,MEM_RELEASE)==0)
312+
elog(FATAL,"failed to release reserved memory region (addr=%p): error code %lu",
313+
ShmemProtectiveRegion,GetLastError());
282314
if (VirtualFree(UsedShmemSegAddr,0,MEM_RELEASE)==0)
283315
elog(FATAL,"failed to release reserved memory region (addr=%p): error code %lu",
284316
UsedShmemSegAddr,GetLastError());
@@ -307,13 +339,14 @@ PGSharedMemoryReAttach(void)
307339
* The child process startup logic might or might not call PGSharedMemoryDetach
308340
* after this; make sure that it will be a no-op if called.
309341
*
310-
* UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this
311-
* routine. The caller must have already restored them to the postmaster's
312-
* values.
342+
*ShmemProtectiveRegion,UsedShmemSegID and UsedShmemSegAddr are implicit
343+
*parameters to thisroutine. The caller must have already restored them to
344+
*the postmaster'svalues.
313345
*/
314346
void
315347
PGSharedMemoryNoReAttach(void)
316348
{
349+
Assert(ShmemProtectiveRegion!=NULL);
317350
Assert(UsedShmemSegAddr!=NULL);
318351
Assert(IsUnderPostmaster);
319352

@@ -340,12 +373,25 @@ PGSharedMemoryNoReAttach(void)
340373
* Rather, this is for subprocesses that have inherited an attachment and want
341374
* to get rid of it.
342375
*
343-
* UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this
344-
* routine.
376+
*ShmemProtectiveRegion,UsedShmemSegID and UsedShmemSegAddr are implicit
377+
*parameters to thisroutine.
345378
*/
346379
void
347380
PGSharedMemoryDetach(void)
348381
{
382+
/*
383+
* Releasing the protective region liberates an unimportant quantity of
384+
* address space, but be tidy.
385+
*/
386+
if (ShmemProtectiveRegion!=NULL)
387+
{
388+
if (VirtualFree(ShmemProtectiveRegion,0,MEM_RELEASE)==0)
389+
elog(LOG,"failed to release reserved memory region (addr=%p): error code %lu",
390+
ShmemProtectiveRegion,GetLastError());
391+
392+
ShmemProtectiveRegion=NULL;
393+
}
394+
349395
/* Unmap the view, if it's mapped */
350396
if (UsedShmemSegAddr!=NULL)
351397
{
@@ -403,29 +449,47 @@ pgwin32_ReserveSharedMemoryRegion(HANDLE hChild)
403449
{
404450
void*address;
405451

452+
Assert(ShmemProtectiveRegion!=NULL);
406453
Assert(UsedShmemSegAddr!=NULL);
407454
Assert(UsedShmemSegSize!=0);
408455

409-
address=VirtualAllocEx(hChild,UsedShmemSegAddr,UsedShmemSegSize,
410-
MEM_RESERVE,PAGE_READWRITE);
456+
/* ShmemProtectiveRegion */
457+
address=VirtualAllocEx(hChild,ShmemProtectiveRegion,
458+
PROTECTIVE_REGION_SIZE,
459+
MEM_RESERVE,PAGE_NOACCESS);
411460
if (address==NULL)
412461
{
413462
/* Don't use FATAL since we're running in the postmaster */
414463
elog(LOG,"could not reserve shared memory region (addr=%p) for child %p: error code %lu",
415-
UsedShmemSegAddr,hChild,GetLastError());
464+
ShmemProtectiveRegion,hChild,GetLastError());
416465
return false;
417466
}
418-
if (address!=UsedShmemSegAddr)
467+
if (address!=ShmemProtectiveRegion)
419468
{
420469
/*
421470
* Should never happen - in theory if allocation granularity causes
422471
* strange effects it could, so check just in case.
423472
*
424473
* Don't use FATAL since we're running in the postmaster.
425474
*/
475+
elog(LOG,"reserved shared memory region got incorrect address %p, expected %p",
476+
address,ShmemProtectiveRegion);
477+
return false;
478+
}
479+
480+
/* UsedShmemSegAddr */
481+
address=VirtualAllocEx(hChild,UsedShmemSegAddr,UsedShmemSegSize,
482+
MEM_RESERVE,PAGE_READWRITE);
483+
if (address==NULL)
484+
{
485+
elog(LOG,"could not reserve shared memory region (addr=%p) for child %p: error code %lu",
486+
UsedShmemSegAddr,hChild,GetLastError());
487+
return false;
488+
}
489+
if (address!=UsedShmemSegAddr)
490+
{
426491
elog(LOG,"reserved shared memory region got incorrect address %p, expected %p",
427492
address,UsedShmemSegAddr);
428-
VirtualFreeEx(hChild,address,0,MEM_RELEASE);
429493
return false;
430494
}
431495

‎src/backend/postmaster/postmaster.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ typedef struct
493493
#ifndefWIN32
494494
unsigned longUsedShmemSegID;
495495
#else
496+
void*ShmemProtectiveRegion;
496497
HANDLEUsedShmemSegID;
497498
#endif
498499
void*UsedShmemSegAddr;
@@ -6027,6 +6028,9 @@ save_backend_variables(BackendParameters *param, Port *port,
60276028
param->MyCancelKey=MyCancelKey;
60286029
param->MyPMChildSlot=MyPMChildSlot;
60296030

6031+
#ifdefWIN32
6032+
param->ShmemProtectiveRegion=ShmemProtectiveRegion;
6033+
#endif
60306034
param->UsedShmemSegID=UsedShmemSegID;
60316035
param->UsedShmemSegAddr=UsedShmemSegAddr;
60326036

@@ -6260,6 +6264,9 @@ restore_backend_variables(BackendParameters *param, Port *port)
62606264
MyCancelKey=param->MyCancelKey;
62616265
MyPMChildSlot=param->MyPMChildSlot;
62626266

6267+
#ifdefWIN32
6268+
ShmemProtectiveRegion=param->ShmemProtectiveRegion;
6269+
#endif
62636270
UsedShmemSegID=param->UsedShmemSegID;
62646271
UsedShmemSegAddr=param->UsedShmemSegAddr;
62656272

‎src/include/storage/pg_shmem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ typedef enum
5656
externunsigned longUsedShmemSegID;
5757
#else
5858
externHANDLEUsedShmemSegID;
59+
externvoid*ShmemProtectiveRegion;
5960
#endif
6061
externvoid*UsedShmemSegAddr;
6162

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp