LCOV - differential code coverage report
Current view: top level - src/backend/port - posix_sema.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 71.7 % 60 43 17 43
Current Date: 2024-04-14 14:21:10 Functions: 90.0 % 10 9 1 9
Baseline: 16@8cea358b128 Branches: 24.1 % 58 14 44 14
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 71.7 % 60 43 17 43
Function coverage date bins:
(240..) days: 90.0 % 10 9 1 9
Branch coverage date bins:
(240..) days: 24.1 % 58 14 44 14

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * posix_sema.c
                                  4                 :                :  *    Implement PGSemaphores using POSIX semaphore facilities
                                  5                 :                :  *
                                  6                 :                :  * We prefer the unnamed style of POSIX semaphore (the kind made with
                                  7                 :                :  * sem_init).  We can cope with the kind made with sem_open, however.
                                  8                 :                :  *
                                  9                 :                :  * In either implementation, typedef PGSemaphore is equivalent to "sem_t *".
                                 10                 :                :  * With unnamed semaphores, the sem_t structs live in an array in shared
                                 11                 :                :  * memory.  With named semaphores, that's not true because we cannot persuade
                                 12                 :                :  * sem_open to do its allocation there.  Therefore, the named-semaphore code
                                 13                 :                :  * *does not cope with EXEC_BACKEND*.  The sem_t structs will just be in the
                                 14                 :                :  * postmaster's private memory, where they are successfully inherited by
                                 15                 :                :  * forked backends, but they could not be accessed by exec'd backends.
                                 16                 :                :  *
                                 17                 :                :  *
                                 18                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                 19                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 20                 :                :  *
                                 21                 :                :  * IDENTIFICATION
                                 22                 :                :  *    src/backend/port/posix_sema.c
                                 23                 :                :  *
                                 24                 :                :  *-------------------------------------------------------------------------
                                 25                 :                :  */
                                 26                 :                : #include "postgres.h"
                                 27                 :                : 
                                 28                 :                : #include <fcntl.h>
                                 29                 :                : #include <semaphore.h>
                                 30                 :                : #include <signal.h>
                                 31                 :                : #include <unistd.h>
                                 32                 :                : #include <sys/stat.h>
                                 33                 :                : 
                                 34                 :                : #include "miscadmin.h"
                                 35                 :                : #include "storage/ipc.h"
                                 36                 :                : #include "storage/pg_sema.h"
                                 37                 :                : #include "storage/shmem.h"
                                 38                 :                : 
                                 39                 :                : 
                                 40                 :                : /* see file header comment */
                                 41                 :                : #if defined(USE_NAMED_POSIX_SEMAPHORES) && defined(EXEC_BACKEND)
                                 42                 :                : #error cannot use named POSIX semaphores with EXEC_BACKEND
                                 43                 :                : #endif
                                 44                 :                : 
                                 45                 :                : typedef union SemTPadded
                                 46                 :                : {
                                 47                 :                :     sem_t       pgsem;
                                 48                 :                :     char        pad[PG_CACHE_LINE_SIZE];
                                 49                 :                : } SemTPadded;
                                 50                 :                : 
                                 51                 :                : /* typedef PGSemaphore is equivalent to pointer to sem_t */
                                 52                 :                : typedef struct PGSemaphoreData
                                 53                 :                : {
                                 54                 :                :     SemTPadded  sem_padded;
                                 55                 :                : } PGSemaphoreData;
                                 56                 :                : 
                                 57                 :                : #define PG_SEM_REF(x)   (&(x)->sem_padded.pgsem)
                                 58                 :                : 
                                 59                 :                : #define IPCProtection   (0600)  /* access/modify by user only */
                                 60                 :                : 
                                 61                 :                : #ifdef USE_NAMED_POSIX_SEMAPHORES
                                 62                 :                : static sem_t **mySemPointers;   /* keep track of created semaphores */
                                 63                 :                : #else
                                 64                 :                : static PGSemaphore sharedSemas; /* array of PGSemaphoreData in shared memory */
                                 65                 :                : #endif
                                 66                 :                : static int  numSems;            /* number of semas acquired so far */
                                 67                 :                : static int  maxSems;            /* allocated size of above arrays */
                                 68                 :                : static int  nextSemKey;         /* next name to try */
                                 69                 :                : 
                                 70                 :                : 
                                 71                 :                : static void ReleaseSemaphores(int status, Datum arg);
                                 72                 :                : 
                                 73                 :                : 
                                 74                 :                : #ifdef USE_NAMED_POSIX_SEMAPHORES
                                 75                 :                : 
                                 76                 :                : /*
                                 77                 :                :  * PosixSemaphoreCreate
                                 78                 :                :  *
                                 79                 :                :  * Attempt to create a new named semaphore.
                                 80                 :                :  *
                                 81                 :                :  * If we fail with a failure code other than collision-with-existing-sema,
                                 82                 :                :  * print out an error and abort.  Other types of errors suggest nonrecoverable
                                 83                 :                :  * problems.
                                 84                 :                :  */
                                 85                 :                : static sem_t *
                                 86                 :                : PosixSemaphoreCreate(void)
                                 87                 :                : {
                                 88                 :                :     int         semKey;
                                 89                 :                :     char        semname[64];
                                 90                 :                :     sem_t      *mySem;
                                 91                 :                : 
                                 92                 :                :     for (;;)
                                 93                 :                :     {
                                 94                 :                :         semKey = nextSemKey++;
                                 95                 :                : 
                                 96                 :                :         snprintf(semname, sizeof(semname), "/pgsql-%d", semKey);
                                 97                 :                : 
                                 98                 :                :         mySem = sem_open(semname, O_CREAT | O_EXCL,
                                 99                 :                :                          (mode_t) IPCProtection, (unsigned) 1);
                                100                 :                : 
                                101                 :                : #ifdef SEM_FAILED
                                102                 :                :         if (mySem != (sem_t *) SEM_FAILED)
                                103                 :                :             break;
                                104                 :                : #else
                                105                 :                :         if (mySem != (sem_t *) (-1))
                                106                 :                :             break;
                                107                 :                : #endif
                                108                 :                : 
                                109                 :                :         /* Loop if error indicates a collision */
                                110                 :                :         if (errno == EEXIST || errno == EACCES || errno == EINTR)
                                111                 :                :             continue;
                                112                 :                : 
                                113                 :                :         /*
                                114                 :                :          * Else complain and abort
                                115                 :                :          */
                                116                 :                :         elog(FATAL, "sem_open(\"%s\") failed: %m", semname);
                                117                 :                :     }
                                118                 :                : 
                                119                 :                :     /*
                                120                 :                :      * Unlink the semaphore immediately, so it can't be accessed externally.
                                121                 :                :      * This also ensures that it will go away if we crash.
                                122                 :                :      */
                                123                 :                :     sem_unlink(semname);
                                124                 :                : 
                                125                 :                :     return mySem;
                                126                 :                : }
                                127                 :                : #else                           /* !USE_NAMED_POSIX_SEMAPHORES */
                                128                 :                : 
                                129                 :                : /*
                                130                 :                :  * PosixSemaphoreCreate
                                131                 :                :  *
                                132                 :                :  * Attempt to create a new unnamed semaphore.
                                133                 :                :  */
                                134                 :                : static void
 2524 bruce@momjian.us          135                 :CBC       79822 : PosixSemaphoreCreate(sem_t *sem)
                                136                 :                : {
 8015 tgl@sss.pgh.pa.us         137         [ -  + ]:          79822 :     if (sem_init(sem, 1, 1) < 0)
 7567 tgl@sss.pgh.pa.us         138         [ #  # ]:UBC           0 :         elog(FATAL, "sem_init failed: %m");
 8015 tgl@sss.pgh.pa.us         139                 :CBC       79822 : }
                                140                 :                : #endif                          /* USE_NAMED_POSIX_SEMAPHORES */
                                141                 :                : 
                                142                 :                : 
                                143                 :                : /*
                                144                 :                :  * PosixSemaphoreKill   - removes a semaphore
                                145                 :                :  */
                                146                 :                : static void
 2524 bruce@momjian.us          147                 :          79822 : PosixSemaphoreKill(sem_t *sem)
                                148                 :                : {
                                149                 :                : #ifdef USE_NAMED_POSIX_SEMAPHORES
                                150                 :                :     /* Got to use sem_close for named semaphores */
                                151                 :                :     if (sem_close(sem) < 0)
                                152                 :                :         elog(LOG, "sem_close failed: %m");
                                153                 :                : #else
                                154                 :                :     /* Got to use sem_destroy for unnamed semaphores */
 8015 tgl@sss.pgh.pa.us         155         [ -  + ]:          79822 :     if (sem_destroy(sem) < 0)
 7567 tgl@sss.pgh.pa.us         156         [ #  # ]:UBC           0 :         elog(LOG, "sem_destroy failed: %m");
                                157                 :                : #endif
 8015 tgl@sss.pgh.pa.us         158                 :CBC       79822 : }
                                159                 :                : 
                                160                 :                : 
                                161                 :                : /*
                                162                 :                :  * Report amount of shared memory needed for semaphores
                                163                 :                :  */
                                164                 :                : Size
 2680                           165                 :           2577 : PGSemaphoreShmemSize(int maxSemas)
                                166                 :                : {
                                167                 :                : #ifdef USE_NAMED_POSIX_SEMAPHORES
                                168                 :                :     /* No shared memory needed in this case */
                                169                 :                :     return 0;
                                170                 :                : #else
                                171                 :                :     /* Need a PGSemaphoreData per semaphore */
                                172                 :           2577 :     return mul_size(maxSemas, sizeof(PGSemaphoreData));
                                173                 :                : #endif
                                174                 :                : }
                                175                 :                : 
                                176                 :                : /*
                                177                 :                :  * PGReserveSemaphores --- initialize semaphore support
                                178                 :                :  *
                                179                 :                :  * This is called during postmaster start or shared memory reinitialization.
                                180                 :                :  * It should do whatever is needed to be able to support up to maxSemas
                                181                 :                :  * subsequent PGSemaphoreCreate calls.  Also, if any system resources
                                182                 :                :  * are acquired here or in PGSemaphoreCreate, register an on_shmem_exit
                                183                 :                :  * callback to release them.
                                184                 :                :  *
                                185                 :                :  * In the Posix implementation, we acquire semaphores on-demand; the
                                186                 :                :  * maxSemas parameter is just used to size the arrays.  For unnamed
                                187                 :                :  * semaphores, there is an array of PGSemaphoreData structs in shared memory.
                                188                 :                :  * For named semaphores, we keep a postmaster-local array of sem_t pointers,
                                189                 :                :  * which we use for releasing the semaphores when done.
                                190                 :                :  * (This design minimizes the dependency of postmaster shutdown on the
                                191                 :                :  * contents of shared memory, which a failed backend might have clobbered.
                                192                 :                :  * We can't do much about the possibility of sem_destroy() crashing, but
                                193                 :                :  * we don't have to expose the counters to other processes.)
                                194                 :                :  */
                                195                 :                : void
 1683                           196                 :            898 : PGReserveSemaphores(int maxSemas)
                                197                 :                : {
                                198                 :                :     struct stat statbuf;
                                199                 :                : 
                                200                 :                :     /*
                                201                 :                :      * We use the data directory's inode number to seed the search for free
                                202                 :                :      * semaphore keys.  This minimizes the odds of collision with other
                                203                 :                :      * postmasters, while maximizing the odds that we will detect and clean up
                                204                 :                :      * semaphores left over from a crashed postmaster in our own directory.
                                205                 :                :      */
                                206         [ -  + ]:            898 :     if (stat(DataDir, &statbuf) < 0)
 1683 tgl@sss.pgh.pa.us         207         [ #  # ]:UBC           0 :         ereport(FATAL,
                                208                 :                :                 (errcode_for_file_access(),
                                209                 :                :                  errmsg("could not stat data directory \"%s\": %m",
                                210                 :                :                         DataDir)));
                                211                 :                : 
                                212                 :                : #ifdef USE_NAMED_POSIX_SEMAPHORES
                                213                 :                :     mySemPointers = (sem_t **) malloc(maxSemas * sizeof(sem_t *));
                                214                 :                :     if (mySemPointers == NULL)
                                215                 :                :         elog(PANIC, "out of memory");
                                216                 :                : #else
                                217                 :                : 
                                218                 :                :     /*
                                219                 :                :      * We must use ShmemAllocUnlocked(), since the spinlock protecting
                                220                 :                :      * ShmemAlloc() won't be ready yet.  (This ordering is necessary when we
                                221                 :                :      * are emulating spinlocks with semaphores.)
                                222                 :                :      */
 2680 tgl@sss.pgh.pa.us         223                 :CBC         898 :     sharedSemas = (PGSemaphore)
                                224                 :            898 :         ShmemAllocUnlocked(PGSemaphoreShmemSize(maxSemas));
                                225                 :                : #endif
                                226                 :                : 
 8015                           227                 :            898 :     numSems = 0;
                                228                 :            898 :     maxSems = maxSemas;
 1683                           229                 :            898 :     nextSemKey = statbuf.st_ino;
                                230                 :                : 
 8015                           231                 :            898 :     on_shmem_exit(ReleaseSemaphores, 0);
                                232                 :            898 : }
                                233                 :                : 
                                234                 :                : /*
                                235                 :                :  * Release semaphores at shutdown or shmem reinitialization
                                236                 :                :  *
                                237                 :                :  * (called as an on_shmem_exit callback, hence funny argument list)
                                238                 :                :  */
                                239                 :                : static void
                                240                 :            898 : ReleaseSemaphores(int status, Datum arg)
                                241                 :                : {
                                242                 :                :     int         i;
                                243                 :                : 
                                244                 :                : #ifdef USE_NAMED_POSIX_SEMAPHORES
                                245                 :                :     for (i = 0; i < numSems; i++)
                                246                 :                :         PosixSemaphoreKill(mySemPointers[i]);
                                247                 :                :     free(mySemPointers);
                                248                 :                : #endif
                                249                 :                : 
                                250                 :                : #ifdef USE_UNNAMED_POSIX_SEMAPHORES
 2680                           251         [ +  + ]:          80720 :     for (i = 0; i < numSems; i++)
                                252                 :          79822 :         PosixSemaphoreKill(PG_SEM_REF(sharedSemas + i));
                                253                 :                : #endif
 8015                           254                 :            898 : }
                                255                 :                : 
                                256                 :                : /*
                                257                 :                :  * PGSemaphoreCreate
                                258                 :                :  *
                                259                 :                :  * Allocate a PGSemaphore structure with initial count 1
                                260                 :                :  */
                                261                 :                : PGSemaphore
 2680                           262                 :          79822 : PGSemaphoreCreate(void)
                                263                 :                : {
                                264                 :                :     PGSemaphore sema;
                                265                 :                :     sem_t      *newsem;
                                266                 :                : 
                                267                 :                :     /* Can't do this in a backend, because static state is postmaster's */
 8015                           268         [ -  + ]:          79822 :     Assert(!IsUnderPostmaster);
                                269                 :                : 
                                270         [ -  + ]:          79822 :     if (numSems >= maxSems)
 7572 tgl@sss.pgh.pa.us         271         [ #  # ]:UBC           0 :         elog(PANIC, "too many semaphores created");
                                272                 :                : 
                                273                 :                : #ifdef USE_NAMED_POSIX_SEMAPHORES
                                274                 :                :     newsem = PosixSemaphoreCreate();
                                275                 :                :     /* Remember new sema for ReleaseSemaphores */
                                276                 :                :     mySemPointers[numSems] = newsem;
                                277                 :                :     sema = (PGSemaphore) newsem;
                                278                 :                : #else
 2680 tgl@sss.pgh.pa.us         279                 :CBC       79822 :     sema = &sharedSemas[numSems];
                                280                 :          79822 :     newsem = PG_SEM_REF(sema);
                                281                 :          79822 :     PosixSemaphoreCreate(newsem);
                                282                 :                : #endif
                                283                 :                : 
                                284                 :          79822 :     numSems++;
                                285                 :                : 
                                286                 :          79822 :     return sema;
                                287                 :                : }
                                288                 :                : 
                                289                 :                : /*
                                290                 :                :  * PGSemaphoreReset
                                291                 :                :  *
                                292                 :                :  * Reset a previously-initialized PGSemaphore to have count 0
                                293                 :                :  */
                                294                 :                : void
 8015                           295                 :          19573 : PGSemaphoreReset(PGSemaphore sema)
                                296                 :                : {
                                297                 :                :     /*
                                298                 :                :      * There's no direct API for this in POSIX, so we have to ratchet the
                                299                 :                :      * semaphore down to 0 with repeated trywait's.
                                300                 :                :      */
                                301                 :                :     for (;;)
                                302                 :                :     {
                                303         [ +  + ]:          30512 :         if (sem_trywait(PG_SEM_REF(sema)) < 0)
                                304                 :                :         {
                                305   [ -  +  -  - ]:          19573 :             if (errno == EAGAIN || errno == EDEADLK)
                                306                 :                :                 break;          /* got it down to 0 */
 8015 tgl@sss.pgh.pa.us         307         [ #  # ]:UBC           0 :             if (errno == EINTR)
                                308                 :              0 :                 continue;       /* can this happen? */
 7567                           309         [ #  # ]:              0 :             elog(FATAL, "sem_trywait failed: %m");
                                310                 :                :         }
                                311                 :                :     }
 8015 tgl@sss.pgh.pa.us         312                 :CBC       19573 : }
                                313                 :                : 
                                314                 :                : /*
                                315                 :                :  * PGSemaphoreLock
                                316                 :                :  *
                                317                 :                :  * Lock a semaphore (decrement count), blocking if count would be < 0
                                318                 :                :  */
                                319                 :                : void
 3358 andres@anarazel.de        320                 :         466363 : PGSemaphoreLock(PGSemaphore sema)
                                321                 :                : {
                                322                 :                :     int         errStatus;
                                323                 :                : 
                                324                 :                :     /* See notes in sysv_sema.c's implementation of PGSemaphoreLock. */
                                325                 :                :     do
                                326                 :                :     {
 8015 tgl@sss.pgh.pa.us         327                 :         466363 :         errStatus = sem_wait(PG_SEM_REF(sema));
                                328   [ -  +  -  - ]:         466363 :     } while (errStatus < 0 && errno == EINTR);
                                329                 :                : 
                                330         [ -  + ]:         466363 :     if (errStatus < 0)
 7567 tgl@sss.pgh.pa.us         331         [ #  # ]:UBC           0 :         elog(FATAL, "sem_wait failed: %m");
 8015 tgl@sss.pgh.pa.us         332                 :CBC      466363 : }
                                333                 :                : 
                                334                 :                : /*
                                335                 :                :  * PGSemaphoreUnlock
                                336                 :                :  *
                                337                 :                :  * Unlock a semaphore (increment count)
                                338                 :                :  */
                                339                 :                : void
                                340                 :         466362 : PGSemaphoreUnlock(PGSemaphore sema)
                                341                 :                : {
                                342                 :                :     int         errStatus;
                                343                 :                : 
                                344                 :                :     /*
                                345                 :                :      * Note: if errStatus is -1 and errno == EINTR then it means we returned
                                346                 :                :      * from the operation prematurely because we were sent a signal.  So we
                                347                 :                :      * try and unlock the semaphore again. Not clear this can really happen,
                                348                 :                :      * but might as well cope.
                                349                 :                :      */
                                350                 :                :     do
                                351                 :                :     {
                                352                 :         466362 :         errStatus = sem_post(PG_SEM_REF(sema));
                                353   [ -  +  -  - ]:         466362 :     } while (errStatus < 0 && errno == EINTR);
                                354                 :                : 
                                355         [ -  + ]:         466362 :     if (errStatus < 0)
 7567 tgl@sss.pgh.pa.us         356         [ #  # ]:UBC           0 :         elog(FATAL, "sem_post failed: %m");
 8015 tgl@sss.pgh.pa.us         357                 :CBC      466362 : }
                                358                 :                : 
                                359                 :                : /*
                                360                 :                :  * PGSemaphoreTryLock
                                361                 :                :  *
                                362                 :                :  * Lock a semaphore only if able to do so without blocking
                                363                 :                :  */
                                364                 :                : bool
 8015 tgl@sss.pgh.pa.us         365                 :UBC           0 : PGSemaphoreTryLock(PGSemaphore sema)
                                366                 :                : {
                                367                 :                :     int         errStatus;
                                368                 :                : 
                                369                 :                :     /*
                                370                 :                :      * Note: if errStatus is -1 and errno == EINTR then it means we returned
                                371                 :                :      * from the operation prematurely because we were sent a signal.  So we
                                372                 :                :      * try and lock the semaphore again.
                                373                 :                :      */
                                374                 :                :     do
                                375                 :                :     {
                                376                 :              0 :         errStatus = sem_trywait(PG_SEM_REF(sema));
                                377   [ #  #  #  # ]:              0 :     } while (errStatus < 0 && errno == EINTR);
                                378                 :                : 
                                379         [ #  # ]:              0 :     if (errStatus < 0)
                                380                 :                :     {
                                381   [ #  #  #  # ]:              0 :         if (errno == EAGAIN || errno == EDEADLK)
                                382                 :              0 :             return false;       /* failed to lock it */
                                383                 :                :         /* Otherwise we got trouble */
 7567                           384         [ #  # ]:              0 :         elog(FATAL, "sem_trywait failed: %m");
                                385                 :                :     }
                                386                 :                : 
 8015                           387                 :              0 :     return true;
                                388                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622