3
3
* sysv_shmem.c
4
4
* Implement shared memory using SysV facilities
5
5
*
6
- * These routines represent a fairly thin layer on top of SysV shared
7
- * memory functionality.
6
+ * These routines used to be a fairly thin layer on top of SysV shared
7
+ * memory functionality. With the addition of anonymous-shmem logic,
8
+ * they're a bit fatter now. We still require a SysV shmem block to
9
+ * exist, though, because mmap'd shmem provides no way to find out how
10
+ * many processes are attached, which we need for interlocking purposes.
8
11
*
9
12
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
10
13
* Portions Copyright (c) 1994, Regents of the University of California
36
39
#include "utils/guc.h"
37
40
38
41
42
+ /*
43
+ * As of PostgreSQL 9.3, we normally allocate only a very small amount of
44
+ * System V shared memory, and only for the purposes of providing an
45
+ * interlock to protect the data directory. The real shared memory block
46
+ * is allocated using mmap(). This works around the problem that many
47
+ * systems have very low limits on the amount of System V shared memory
48
+ * that can be allocated. Even a limit of a few megabytes will be enough
49
+ * to run many copies of PostgreSQL without needing to adjust system settings.
50
+ *
51
+ * We assume that no one will attempt to run PostgreSQL 9.3 or later on
52
+ * systems that are ancient enough that anonymous shared memory is not
53
+ * supported, such as pre-2.4 versions of Linux. If that turns out to be
54
+ * false, we might need to add compile and/or run-time tests here and do this
55
+ * only if the running kernel supports it.
56
+ *
57
+ * However, we must always disable this logic in the EXEC_BACKEND case, and
58
+ * fall back to the old method of allocating the entire segment using System V
59
+ * shared memory, because there's no way to attach an anonymous mmap'd segment
60
+ * to a process after exec(). Since EXEC_BACKEND is intended only for
61
+ * developer use, this shouldn't be a big problem. Because of this, we do
62
+ * not worry about supporting anonymous shmem in the EXEC_BACKEND cases below.
63
+ */
64
+ #ifndef EXEC_BACKEND
65
+ #define USE_ANONYMOUS_SHMEM
66
+ #endif
67
+
68
+
39
69
typedef key_t IpcMemoryKey ; /* shared memory key passed to shmget(2) */
40
70
typedef int IpcMemoryId ; /* shared memory ID returned by shmget(2) */
41
71
42
72
43
73
unsigned long UsedShmemSegID = 0 ;
44
74
void * UsedShmemSegAddr = NULL ;
75
+
76
+ #ifdef USE_ANONYMOUS_SHMEM
45
77
static Size AnonymousShmemSize ;
46
78
static void * AnonymousShmem = NULL ;
79
+ #endif
47
80
48
81
static void * InternalIpcMemoryCreate (IpcMemoryKey memKey , Size size );
49
82
static void IpcMemoryDetach (int status , Datum shmaddr );
@@ -204,10 +237,6 @@ IpcMemoryDetach(int status, Datum shmaddr)
204
237
/* Detach System V shared memory block. */
205
238
if (shmdt (DatumGetPointer (shmaddr )) < 0 )
206
239
elog (LOG , "shmdt(%p) failed: %m" , DatumGetPointer (shmaddr ));
207
- /* Release anonymous shared memory block, if any. */
208
- if (AnonymousShmem != NULL
209
- && munmap (AnonymousShmem , AnonymousShmemSize ) < 0 )
210
- elog (LOG , "munmap(%p) failed: %m" , AnonymousShmem );
211
240
}
212
241
213
242
/****************************************************************************/
@@ -318,14 +347,15 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
318
347
return true;
319
348
}
320
349
350
+ #ifdef USE_ANONYMOUS_SHMEM
351
+
321
352
/*
322
353
* Creates an anonymous mmap()ed shared memory segment.
323
354
*
324
355
* Pass the requested size in *size. This function will modify *size to the
325
356
* actual size of the allocation, if it ends up allocating a segment that is
326
357
* larger than requested.
327
358
*/
328
- #ifndef EXEC_BACKEND
329
359
static void *
330
360
CreateAnonymousSegment (Size * size )
331
361
{
@@ -334,10 +364,8 @@ CreateAnonymousSegment(Size *size)
334
364
int mmap_errno = 0 ;
335
365
336
366
#ifndef MAP_HUGETLB
337
- if (huge_pages == HUGE_PAGES_ON )
338
- ereport (ERROR ,
339
- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
340
- errmsg ("huge TLB pages not supported on this platform" )));
367
+ /* PGSharedMemoryCreate should have dealt with this case */
368
+ Assert (huge_pages != HUGE_PAGES_ON );
341
369
#else
342
370
if (huge_pages == HUGE_PAGES_ON || huge_pages == HUGE_PAGES_TRY )
343
371
{
@@ -366,12 +394,12 @@ CreateAnonymousSegment(Size *size)
366
394
PG_MMAP_FLAGS | MAP_HUGETLB , -1 , 0 );
367
395
mmap_errno = errno ;
368
396
if (huge_pages == HUGE_PAGES_TRY && ptr == MAP_FAILED )
369
- elog (DEBUG1 , "mmap with MAP_HUGETLB failed, huge pages disabled: %m" );
397
+ elog (DEBUG1 , "mmap(%zu) with MAP_HUGETLB failed, huge pages disabled: %m" ,
398
+ allocsize );
370
399
}
371
400
#endif
372
401
373
- if (huge_pages == HUGE_PAGES_OFF ||
374
- (huge_pages == HUGE_PAGES_TRY && ptr == MAP_FAILED ))
402
+ if (ptr == MAP_FAILED && huge_pages != HUGE_PAGES_ON )
375
403
{
376
404
/*
377
405
* use the original size, not the rounded up value, when falling back
@@ -401,7 +429,25 @@ CreateAnonymousSegment(Size *size)
401
429
* size = allocsize ;
402
430
return ptr ;
403
431
}
404
- #endif
432
+
433
+ /*
434
+ * AnonymousShmemDetach --- detach from an anonymous mmap'd block
435
+ * (called as an on_shmem_exit callback, hence funny argument list)
436
+ */
437
+ static void
438
+ AnonymousShmemDetach (int status , Datum arg )
439
+ {
440
+ /* Release anonymous shared memory block, if any. */
441
+ if (AnonymousShmem != NULL )
442
+ {
443
+ if (munmap (AnonymousShmem , AnonymousShmemSize ) < 0 )
444
+ elog (LOG , "munmap(%p, %zu) failed: %m" ,
445
+ AnonymousShmem , AnonymousShmemSize );
446
+ AnonymousShmem = NULL ;
447
+ }
448
+ }
449
+
450
+ #endif /* USE_ANONYMOUS_SHMEM */
405
451
406
452
/*
407
453
* PGSharedMemoryCreate
@@ -432,7 +478,8 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port,
432
478
struct stat statbuf ;
433
479
Size sysvsize ;
434
480
435
- #if defined(EXEC_BACKEND ) || !defined(MAP_HUGETLB )
481
+ /* Complain if hugepages demanded but we can't possibly support them */
482
+ #if !defined(USE_ANONYMOUS_SHMEM ) || !defined(MAP_HUGETLB )
436
483
if (huge_pages == HUGE_PAGES_ON )
437
484
ereport (ERROR ,
438
485
(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
@@ -442,32 +489,13 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port,
442
489
/* Room for a header? */
443
490
Assert (size > MAXALIGN (sizeof (PGShmemHeader )));
444
491
445
- /*
446
- * As of PostgreSQL 9.3, we normally allocate only a very small amount of
447
- * System V shared memory, and only for the purposes of providing an
448
- * interlock to protect the data directory. The real shared memory block
449
- * is allocated using mmap(). This works around the problem that many
450
- * systems have very low limits on the amount of System V shared memory
451
- * that can be allocated. Even a limit of a few megabytes will be enough
452
- * to run many copies of PostgreSQL without needing to adjust system
453
- * settings.
454
- *
455
- * We assume that no one will attempt to run PostgreSQL 9.3 or later on
456
- * systems that are ancient enough that anonymous shared memory is not
457
- * supported, such as pre-2.4 versions of Linux. If that turns out to be
458
- * false, we might need to add a run-time test here and do this only if
459
- * the running kernel supports it.
460
- *
461
- * However, we disable this logic in the EXEC_BACKEND case, and fall back
462
- * to the old method of allocating the entire segment using System V
463
- * shared memory, because there's no way to attach an mmap'd segment to a
464
- * process after exec(). Since EXEC_BACKEND is intended only for
465
- * developer use, this shouldn't be a big problem.
466
- */
467
- #ifndef EXEC_BACKEND
492
+ #ifdef USE_ANONYMOUS_SHMEM
468
493
AnonymousShmem = CreateAnonymousSegment (& size );
469
494
AnonymousShmemSize = size ;
470
495
496
+ /* Register on-exit routine to unmap the anonymous segment */
497
+ on_shmem_exit (AnonymousShmemDetach , (Datum ) 0 );
498
+
471
499
/* Now we need only allocate a minimal-sized SysV shmem block. */
472
500
sysvsize = sizeof (PGShmemHeader );
473
501
#else
@@ -572,10 +600,14 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port,
572
600
* block. Otherwise, the System V shared memory block is only a shim, and
573
601
* we must return a pointer to the real block.
574
602
*/
603
+ #ifdef USE_ANONYMOUS_SHMEM
575
604
if (AnonymousShmem == NULL )
576
605
return hdr ;
577
606
memcpy (AnonymousShmem , hdr , sizeof (PGShmemHeader ));
578
607
return (PGShmemHeader * ) AnonymousShmem ;
608
+ #else
609
+ return hdr ;
610
+ #endif
579
611
}
580
612
581
613
#ifdef EXEC_BACKEND
@@ -660,12 +692,12 @@ PGSharedMemoryNoReAttach(void)
660
692
*
661
693
* Detach from the shared memory segment, if still attached. This is not
662
694
* intended to be called explicitly by the process that originally created the
663
- * segment (it will have an on_shmem_exit callback registered to do that).
695
+ * segment (it will have on_shmem_exit callback(s) registered to do that).
664
696
* Rather, this is for subprocesses that have inherited an attachment and want
665
697
* to get rid of it.
666
698
*
667
699
* UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this
668
- * routine.
700
+ * routine, also AnonymousShmem and AnonymousShmemSize .
669
701
*/
670
702
void
671
703
PGSharedMemoryDetach (void )
@@ -682,10 +714,15 @@ PGSharedMemoryDetach(void)
682
714
UsedShmemSegAddr = NULL ;
683
715
}
684
716
685
- /* Release anonymous shared memory block, if any. */
686
- if (AnonymousShmem != NULL
687
- && munmap (AnonymousShmem , AnonymousShmemSize ) < 0 )
688
- elog (LOG , "munmap(%p) failed: %m" , AnonymousShmem );
717
+ #ifdef USE_ANONYMOUS_SHMEM
718
+ if (AnonymousShmem != NULL )
719
+ {
720
+ if (munmap (AnonymousShmem , AnonymousShmemSize ) < 0 )
721
+ elog (LOG , "munmap(%p, %zu) failed: %m" ,
722
+ AnonymousShmem , AnonymousShmemSize );
723
+ AnonymousShmem = NULL ;
724
+ }
725
+ #endif
689
726
}
690
727
691
728
0 commit comments