Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/doc/src/sgml/ref/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 9 kB image not shown  

Quelle  latch.c   Sprache: unbekannt

 
/*-------------------------------------------------------------------------
 *
 * latch.c
 *   Routines for inter-process latches
 *
 * The latch interface is a reliable replacement for the common pattern of
 * using pg_usleep() or select() to wait until a signal arrives, where the
 * signal handler sets a flag variable.  See latch.h for more information
 * on how to use them.
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *   src/backend/storage/ipc/latch.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "miscadmin.h"
#include "port/atomics.h"
#include "storage/latch.h"
#include "storage/waiteventset.h"
#include "utils/resowner.h"

/* A common WaitEventSet used to implement WaitLatch() */
static WaitEventSet *LatchWaitSet;

/* The positions of the latch and PM death events in LatchWaitSet */
#define LatchWaitSetLatchPos 0
#define LatchWaitSetPostmasterDeathPos 1

void
InitializeLatchWaitSet(void)
{
 int   latch_pos PG_USED_FOR_ASSERTS_ONLY;

 Assert(LatchWaitSet == NULL);

 /* Set up the WaitEventSet used by WaitLatch(). */
 LatchWaitSet = CreateWaitEventSet(NULL, 2);
 latch_pos = AddWaitEventToSet(LatchWaitSet, WL_LATCH_SET, PGINVALID_SOCKET,
          MyLatch, NULL);
 Assert(latch_pos == LatchWaitSetLatchPos);

 /*
  * WaitLatch will modify this to WL_EXIT_ON_PM_DEATH or
  * WL_POSTMASTER_DEATH on each call.
 */

 if (IsUnderPostmaster)
 {
  latch_pos = AddWaitEventToSet(LatchWaitSet, WL_EXIT_ON_PM_DEATH,
           PGINVALID_SOCKET, NULL, NULL);
  Assert(latch_pos == LatchWaitSetPostmasterDeathPos);
 }
}

/*
 * Initialize a process-local latch.
 */

void
InitLatch(Latch *latch)
{
 latch->is_set = false;
 latch->maybe_sleeping = false;
 latch->owner_pid = MyProcPid;
 latch->is_shared = false;

#ifdef WIN32
 latch->event = CreateEvent(NULL, TRUEFALSE, NULL);
 if (latch->event == NULL)
  elog(ERROR, "CreateEvent failed: error code %lu", GetLastError());
#endif       /* WIN32 */
}

/*
 * Initialize a shared latch that can be set from other processes. The latch
 * is initially owned by no-one; use OwnLatch to associate it with the
 * current process.
 *
 * InitSharedLatch needs to be called in postmaster before forking child
 * processes, usually right after allocating the shared memory block
 * containing the latch with ShmemInitStruct. (The Unix implementation
 * doesn't actually require that, but the Windows one does.) Because of
 * this restriction, we have no concurrency issues to worry about here.
 *
 * Note that other handles created in this module are never marked as
 * inheritable.  Thus we do not need to worry about cleaning up child
 * process references to postmaster-private latches or WaitEventSets.
 */

void
InitSharedLatch(Latch *latch)
{
#ifdef WIN32
 SECURITY_ATTRIBUTES sa;

 /*
  * Set up security attributes to specify that the events are inherited.
 */

 ZeroMemory(&sa, sizeof(sa));
 sa.nLength = sizeof(sa);
 sa.bInheritHandle = TRUE;

 latch->event = CreateEvent(&sa, TRUEFALSE, NULL);
 if (latch->event == NULL)
  elog(ERROR, "CreateEvent failed: error code %lu", GetLastError());
#endif

 latch->is_set = false;
 latch->maybe_sleeping = false;
 latch->owner_pid = 0;
 latch->is_shared = true;
}

/*
 * Associate a shared latch with the current process, allowing it to
 * wait on the latch.
 *
 * Although there is a sanity check for latch-already-owned, we don't do
 * any sort of locking here, meaning that we could fail to detect the error
 * if two processes try to own the same latch at about the same time.  If
 * there is any risk of that, caller must provide an interlock to prevent it.
 */

void
OwnLatch(Latch *latch)
{
 int   owner_pid;

 /* Sanity checks */
 Assert(latch->is_shared);

 owner_pid = latch->owner_pid;
 if (owner_pid != 0)
  elog(PANIC, "latch already owned by PID %d", owner_pid);

 latch->owner_pid = MyProcPid;
}

/*
 * Disown a shared latch currently owned by the current process.
 */

void
DisownLatch(Latch *latch)
{
 Assert(latch->is_shared);
 Assert(latch->owner_pid == MyProcPid);

 latch->owner_pid = 0;
}

/*
 * Wait for a given latch to be set, or for postmaster death, or until timeout
 * is exceeded. 'wakeEvents' is a bitmask that specifies which of those events
 * to wait for. If the latch is already set (and WL_LATCH_SET is given), the
 * function returns immediately.
 *
 * The "timeout" is given in milliseconds. It must be >= 0 if WL_TIMEOUT flag
 * is given.  Although it is declared as "long", we don't actually support
 * timeouts longer than INT_MAX milliseconds.  Note that some extra overhead
 * is incurred when WL_TIMEOUT is given, so avoid using a timeout if possible.
 *
 * The latch must be owned by the current process, ie. it must be a
 * process-local latch initialized with InitLatch, or a shared latch
 * associated with the current process by calling OwnLatch.
 *
 * Returns bit mask indicating which condition(s) caused the wake-up. Note
 * that if multiple wake-up conditions are true, there is no guarantee that
 * we return all of them in one call, but we will return at least one.
 */

int
WaitLatch(Latch *latch, int wakeEvents, long timeout,
    uint32 wait_event_info)
{
 WaitEvent event;

 /* Postmaster-managed callers must handle postmaster death somehow. */
 Assert(!IsUnderPostmaster ||
     (wakeEvents & WL_EXIT_ON_PM_DEATH) ||
     (wakeEvents & WL_POSTMASTER_DEATH));

 /*
  * Some callers may have a latch other than MyLatch, or no latch at all,
  * or want to handle postmaster death differently.  It's cheap to assign
  * those, so just do it every time.
 */

 if (!(wakeEvents & WL_LATCH_SET))
  latch = NULL;
 ModifyWaitEvent(LatchWaitSet, LatchWaitSetLatchPos, WL_LATCH_SET, latch);

 if (IsUnderPostmaster)
  ModifyWaitEvent(LatchWaitSet, LatchWaitSetPostmasterDeathPos,
      (wakeEvents & (WL_EXIT_ON_PM_DEATH | WL_POSTMASTER_DEATH)),
      NULL);

 if (WaitEventSetWait(LatchWaitSet,
       (wakeEvents & WL_TIMEOUT) ? timeout : -1,
       &event, 1,
       wait_event_info) == 0)
  return WL_TIMEOUT;
 else
  return event.events;
}

/*
 * Like WaitLatch, but with an extra socket argument for WL_SOCKET_*
 * conditions.
 *
 * When waiting on a socket, EOF and error conditions always cause the socket
 * to be reported as readable/writable/connected, so that the caller can deal
 * with the condition.
 *
 * wakeEvents must include either WL_EXIT_ON_PM_DEATH for automatic exit
 * if the postmaster dies or WL_POSTMASTER_DEATH for a flag set in the
 * return value if the postmaster dies.  The latter is useful for rare cases
 * where some behavior other than immediate exit is needed.
 *
 * NB: These days this is just a wrapper around the WaitEventSet API. When
 * using a latch very frequently, consider creating a longer living
 * WaitEventSet instead; that's more efficient.
 */

int
WaitLatchOrSocket(Latch *latch, int wakeEvents, pgsocket sock,
      long timeout, uint32 wait_event_info)
{
 int   ret = 0;
 int   rc;
 WaitEvent event;
 WaitEventSet *set = CreateWaitEventSet(CurrentResourceOwner, 3);

 if (wakeEvents & WL_TIMEOUT)
  Assert(timeout >= 0);
 else
  timeout = -1;

 if (wakeEvents & WL_LATCH_SET)
  AddWaitEventToSet(set, WL_LATCH_SET, PGINVALID_SOCKET,
        latch, NULL);

 /* Postmaster-managed callers must handle postmaster death somehow. */
 Assert(!IsUnderPostmaster ||
     (wakeEvents & WL_EXIT_ON_PM_DEATH) ||
     (wakeEvents & WL_POSTMASTER_DEATH));

 if ((wakeEvents & WL_POSTMASTER_DEATH) && IsUnderPostmaster)
  AddWaitEventToSet(set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
        NULL, NULL);

 if ((wakeEvents & WL_EXIT_ON_PM_DEATH) && IsUnderPostmaster)
  AddWaitEventToSet(set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
        NULL, NULL);

 if (wakeEvents & WL_SOCKET_MASK)
 {
  int   ev;

  ev = wakeEvents & WL_SOCKET_MASK;
  AddWaitEventToSet(set, ev, sock, NULL, NULL);
 }

 rc = WaitEventSetWait(set, timeout, &event, 1, wait_event_info);

 if (rc == 0)
  ret |= WL_TIMEOUT;
 else
 {
  ret |= event.events & (WL_LATCH_SET |
          WL_POSTMASTER_DEATH |
          WL_SOCKET_MASK);
 }

 FreeWaitEventSet(set);

 return ret;
}

/*
 * Sets a latch and wakes up anyone waiting on it.
 *
 * This is cheap if the latch is already set, otherwise not so much.
 *
 * NB: when calling this in a signal handler, be sure to save and restore
 * errno around it.  (That's standard practice in most signal handlers, of
 * course, but we used to omit it in handlers that only set a flag.)
 *
 * NB: this function is called from critical sections and signal handlers so
 * throwing an error is not a good idea.
 */

void
SetLatch(Latch *latch)
{
#ifndef WIN32
 pid_t  owner_pid;
#else
 HANDLE  handle;
#endif

 /*
  * The memory barrier has to be placed here to ensure that any flag
  * variables possibly changed by this process have been flushed to main
  * memory, before we check/set is_set.
 */

 pg_memory_barrier();

 /* Quick exit if already set */
 if (latch->is_set)
  return;

 latch->is_set = true;

 pg_memory_barrier();
 if (!latch->maybe_sleeping)
  return;

#ifndef WIN32

 /*
  * See if anyone's waiting for the latch. It can be the current process if
  * we're in a signal handler. We use the self-pipe or SIGURG to ourselves
  * to wake up WaitEventSetWaitBlock() without races in that case. If it's
  * another process, send a signal.
  *
  * Fetch owner_pid only once, in case the latch is concurrently getting
  * owned or disowned. XXX: This assumes that pid_t is atomic, which isn't
  * guaranteed to be true! In practice, the effective range of pid_t fits
  * in a 32 bit integer, and so should be atomic. In the worst case, we
  * might end up signaling the wrong process. Even then, you're very
  * unlucky if a process with that bogus pid exists and belongs to
  * Postgres; and PG database processes should handle excess SIGUSR1
  * interrupts without a problem anyhow.
  *
  * Another sort of race condition that's possible here is for a new
  * process to own the latch immediately after we look, so we don't signal
  * it. This is okay so long as all callers of ResetLatch/WaitLatch follow
  * the standard coding convention of waiting at the bottom of their loops,
  * not the top, so that they'll correctly process latch-setting events
  * that happen before they enter the loop.
 */

 owner_pid = latch->owner_pid;
 if (owner_pid == 0)
  return;
 else if (owner_pid == MyProcPid)
  WakeupMyProc();
 else
  WakeupOtherProc(owner_pid);

#else

 /*
  * See if anyone's waiting for the latch. It can be the current process if
  * we're in a signal handler.
  *
  * Use a local variable here just in case somebody changes the event field
  * concurrently (which really should not happen).
 */

 handle = latch->event;
 if (handle)
 {
  SetEvent(handle);

  /*
   * Note that we silently ignore any errors. We might be in a signal
   * handler or other critical path where it's not safe to call elog().
 */

 }
#endif
}

/*
 * Clear the latch. Calling WaitLatch after this will sleep, unless
 * the latch is set again before the WaitLatch call.
 */

void
ResetLatch(Latch *latch)
{
 /* Only the owner should reset the latch */
 Assert(latch->owner_pid == MyProcPid);
 Assert(latch->maybe_sleeping == false);

 latch->is_set = false;

 /*
  * Ensure that the write to is_set gets flushed to main memory before we
  * examine any flag variables.  Otherwise a concurrent SetLatch might
  * falsely conclude that it needn't signal us, even though we have missed
  * seeing some flag updates that SetLatch was supposed to inform us of.
 */

 pg_memory_barrier();
}

Messung V0.5 in Prozent
C=93 H=90 G=91

[0.18QuellennavigatorsProjekt 2026-08-08]