text: /*--------------------------------------------------------------------
   * bgworker.c
   *		POSTGRES pluggable background workers implementation
   *
   * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
   *
   * IDENTIFICATION
   *	  src/backend/postmaster/bgworker.c
   *
   *-------------------------------------------------------------------------
   */
  
  #include "postgres.h"
  
  #include <unistd.h>
  
  #include "libpq/pqsignal.h"
  #include "miscadmin.h"
  #include "pgstat.h"
  #include "port/atomics.h"
  #include "postmaster/bgworker_internals.h"
  #include "postmaster/postmaster.h"
  #include "replication/logicallauncher.h"
  #include "storage/dsm.h"
  #include "storage/ipc.h"
  #include "storage/latch.h"
  #include "storage/lwlock.h"
  #include "storage/pg_shmem.h"
  #include "storage/pmsignal.h"
  #include "storage/proc.h"
  #include "storage/procsignal.h"
  #include "storage/shmem.h"
  #include "tcop/tcopprot.h"
  #include "utils/ascii.h"
  #include "utils/ps_status.h"
  #include "utils/timeout.h"
  
  /*
   * The postmaster's list of registered background workers, in private memory.
   */
  slist_head	BackgroundWorkerList = SLIST_STATIC_INIT(BackgroundWorkerList);
  
  /*
   * BackgroundWorkerSlots exist in shared memory and can be accessed (via
   * the BackgroundWorkerArray) by both the postmaster and by regular backends.
   * However, the postmaster cannot take locks, even spinlocks, because this
   * might allow it to crash or become wedged if shared memory gets corrupted.
   * Such an outcome is intolerable.  Therefore, we need a lockless protocol
   * for coordinating access to this data.
   *
   * The 'in_use' flag is used to hand off responsibility for the slot between
   * the postmaster and the rest of the system.  When 'in_use' is false,
   * the postmaster will ignore the slot entirely, except for the 'in_use' flag
   * itself, which it may read.  In this state, regular backends may modify the
   * slot.  Once a backend sets 'in_use' to true, the slot becomes the
   * responsibility of the postmaster.  Regular backends may no longer modify it,
   * but the postmaster may examine it.  Thus, a backend initializing a slot
   * must fully initialize the slot - and insert a write memory barrier - before
   * marking it as in use.
   *
   * As an exception, however, even when the slot is in use, regular backends
   * may set the 'terminate' flag for a slot, telling the postmaster not
   * to restart it.  Once the background worker is no longer running, the slot
   * will be released for reuse.
   *
   * In addition to coordinating with the postmaster, backends modifying this
   * data structure must coordinate with each other.  Since they can take locks,
   * this is straightforward: any backend wishing to manipulate a slot must
   * take BackgroundWorkerLock in exclusive mode.  Backends wishing to read
   * data that might get concurrently modified by other backends should take
   * this lock in shared mode.  No matter what, backends reading this data
   * structure must be able to tolerate concurrent modifications by the
   * postmaster.
   */
  typedef struct BackgroundWorkerSlot
  {
  	bool		in_use;
  	bool		terminate;
  	pid_t		pid;			/* InvalidPid = not started yet; 0 = dead */
  	uint64		generation;		/* incremented when slot is recycled */
  	BackgroundWorker worker;
  } BackgroundWorkerSlot;
  
  /*
   * In order to limit the total number of parallel workers (according to
   * max_parallel_workers GUC), we maintain the number of active parallel
   * workers.  Since the postmaster cannot take locks, two variables are used for
   * this purpose: the number of registered parallel workers (modified by the
   * backends, protected by BackgroundWorkerLock) and the number of terminated
   * parallel workers (modified only by the postmaster, lockless).  The active
   * number of parallel workers is the number of registered workers minus the
   * terminated ones.  These counters can of course overflow, but it's not
   * important here since the subtraction will still give the right number.
   */
  typedef struct BackgroundWorkerArray
  {
  	int			total_slots;
  	uint32		parallel_register_count;
  	uint32		parallel_terminate_count;
  	BackgroundWorkerSlot slot[FLEXIBLE_ARRAY_MEMBER];
  } BackgroundWorkerArray;
  
  struct BackgroundWorkerHandle
  {
  	int			slot;
  	uint64		generation;
  };
  
  static BackgroundWorkerArray *BackgroundWorkerData;
  
  /*
   * List of workers that are allowed to be started outside of
   * shared_preload_libraries.
   */
  static const bgworker_main_type InternalBGWorkers[] = {
  	ApplyLauncherMain,
  	NULL
  };
  
  /*
   * Calculate shared memory needed.
   */
  Size
  BackgroundWorkerShmemSize(void)
  {
  	Size		size;
  
  	/* Array of workers is variably sized. */
  	size = offsetof(BackgroundWorkerArray, slot);
  	size = add_size(size, mul_size(max_worker_processes,
  								   sizeof(BackgroundWorkerSlot)));
  
  	return size;
  }
  
  /*
   * Initialize shared memory.
   */
  void
  BackgroundWorkerShmemInit(void)
  {
  	bool		found;
  
  	BackgroundWorkerData = ShmemInitStruct("Background Worker Data",
  										   BackgroundWorkerShmemSize(),
  										   &found);
  	if (!IsUnderPostmaster)
  	{
  		slist_iter	siter;
  		int			slotno = 0;
  
  		BackgroundWorkerData->total_slots = max_worker_processes;
  		BackgroundWorkerData->parallel_register_count = 0;
  		BackgroundWorkerData->parallel_terminate_count = 0;
  
  		/*
  		 * Copy contents of worker list into shared memory.  Record the shared
  		 * memory slot assigned to each worker.  This ensures a 1-to-1
  		 * correspondence between the postmaster's private list and the array
  		 * in shared memory.
  		 */
  		slist_foreach(siter, &BackgroundWorkerList)
  		{
  			BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno];
  			RegisteredBgWorker *rw;
  
  			rw = slist_container(RegisteredBgWorker, rw_lnode, siter.cur);
  			Assert(slotno < max_worker_processes);
  			slot->in_use = true;
  			slot->terminate = false;
  			slot->pid = InvalidPid;
  			slot->generation = 0;
  			rw->rw_shmem_slot = slotno;
  			rw->rw_worker.bgw_notify_pid = 0;	/* might be reinit after crash */
  			memcpy(&slot->worker, &rw->rw_worker, sizeof(BackgroundWorker));
  			++slotno;
  		}
  
  		/*
  		 * Mark any remaining slots as not in use.
  		 */
  		while (slotno < max_worker_processes)
  		{
  			BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno];
  
  			slot->in_use = false;
  			++slotno;
  		}
  	}
  	else
  		Assert(found);
  }
  
  /*
   * Search the postmaster's backend-private list of RegisteredBgWorker objects
   * for the one that maps to the given slot number.
   */
  static RegisteredBgWorker *
  FindRegisteredWorkerBySlotNumber(int slotno)
  {
  	slist_iter	siter;
  
  	slist_foreach(siter, &BackgroundWorkerList)
  	{
  		RegisteredBgWorker *rw;
  
  		rw = slist_container(RegisteredBgWorker, rw_lnode, siter.cur);
  		if (rw->rw_shmem_slot == slotno)
  			return rw;
  	}
  
  	return NULL;
  }
  
  /*
   * Notice changes to shared memory made by other backends.  This code
   * runs in the postmaster, so we must be very careful not to assume that
   * shared memory contents are sane.  Otherwise, a rogue backend could take
   * out the postmaster.
   */
  void
  BackgroundWorkerStateChange(void)
  {
  	int			slotno;
  
  	/*
  	 * The total number of slots stored in shared memory should match our
  	 * notion of max_worker_processes.  If it does not, something is very
  	 * wrong.  Further down, we always refer to this value as
  	 * max_worker_processes, in case shared memory gets corrupted while we're
  	 * looping.
  	 */
  	if (max_worker_processes != BackgroundWorkerData->total_slots)
  	{
  		elog(LOG,
  			 "inconsistent background worker state (max_worker_processes=%d, total_slots=%d",
  			 max_worker_processes,
  			 BackgroundWorkerData->total_slots);
  		return;
  	}
  
  	/*
  	 * Iterate through slots, looking for newly-registered workers or workers
  	 * who must die.
  	 */
  	for (slotno = 0; slotno < max_worker_processes; ++slotno)
  	{
  		BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno];
  		RegisteredBgWorker *rw;
  
  		if (!slot->in_use)
  			continue;
  
  		/*
  		 * Make sure we don't see the in_use flag before the updated slot
  		 * contents.
  		 */
  		pg_read_barrier();
  
  		/* See whether we already know about this worker. */
  		rw = FindRegisteredWorkerBySlotNumber(slotno);
  		if (rw != NULL)
  		{
  			/*
  			 * In general, the worker data can't change after it's initially
  			 * registered.  However, someone can set the terminate flag.
  			 */
  			if (slot->terminate && !rw->rw_terminate)
  			{
  				rw->rw_terminate = true;
  				if (rw->rw_pid != 0)
  					kill(rw->rw_pid, SIGTERM);
  				else
  				{
  					/* Report never-started, now-terminated worker as dead. */
  					ReportBackgroundWorkerPID(rw);
  				}
  			}
  			continue;
  		}
  
  		/*
  		 * If the worker is marked for termination, we don't need to add it to
  		 * the registered workers list; we can just free the slot. However, if
  		 * bgw_notify_pid is set, the process that registered the worker may
  		 * need to know that we've processed the terminate request, so be sure
  		 * to signal it.
  		 */
  		if (slot->terminate)
  		{
  			int			notify_pid;
  
  			/*
  			 * We need a memory barrier here to make sure that the load of
  			 * bgw_notify_pid and the update of parallel_terminate_count
  			 * complete before the store to in_use.
  			 */
  			notify_pid = slot->worker.bgw_notify_pid;
  			if ((slot->worker.bgw_flags & BGWORKER_CLASS_PARALLEL) != 0)
  				BackgroundWorkerData->parallel_terminate_count++;
  			pg_memory_barrier();
  			slot->pid = 0;
  			slot->in_use = false;
  			if (notify_pid != 0)
  				kill(notify_pid, SIGUSR1);
  
  			continue;
  		}
  
  		/*
  		 * Copy the registration data into the registered workers list.
  		 */
  		rw = malloc(sizeof(RegisteredBgWorker));
  		if (rw == NULL)
  		{
  			ereport(LOG,
  					(errcode(ERRCODE_OUT_OF_MEMORY),
  					 errmsg("out of memory")));
  			return;
  		}
  
  		/*
  		 * Copy strings in a paranoid way.  If shared memory is corrupted, the
  		 * source data might not even be NUL-terminated.
  		 */
  		ascii_safe_strlcpy(rw->rw_worker.bgw_name,
  						   slot->worker.bgw_name, BGW_MAXLEN);
  		ascii_safe_strlcpy(rw->rw_worker.bgw_library_name,
  						   slot->worker.bgw_library_name, BGW_MAXLEN);
  		ascii_safe_strlcpy(rw->rw_worker.bgw_function_name,
  						   slot->worker.bgw_function_name, BGW_MAXLEN);
  
  		/*
  		 * Copy various fixed-size fields.
  		 *
  		 * flags, start_time, and restart_time are examined by the postmaster,
  		 * but nothing too bad will happen if they are corrupted.  The
  		 * remaining fields will only be examined by the child process.  It
  		 * might crash, but we won't.
  		 */
  		rw->rw_worker.bgw_flags = slot->worker.bgw_flags;
  		rw->rw_worker.bgw_start_time = slot->worker.bgw_start_time;
  		rw->rw_worker.bgw_restart_time = slot->worker.bgw_restart_time;
  		rw->rw_worker.bgw_main = slot->worker.bgw_main;
  		rw->rw_worker.bgw_main_arg = slot->worker.bgw_main_arg;
  		memcpy(rw->rw_worker.bgw_extra, slot->worker.bgw_extra, BGW_EXTRALEN);
  
  		/*
  		 * Copy the PID to be notified about state changes, but only if the
  		 * postmaster knows about a backend with that PID.  It isn't an error
  		 * if the postmaster doesn't know about the PID, because the backend
  		 * that requested the worker could have died (or been killed) just
  		 * after doing so.  Nonetheless, at least until we get some experience
  		 * with how this plays out in the wild, log a message at a relative
  		 * high debug level.
  		 */
  		rw->rw_worker.bgw_notify_pid = slot->worker.bgw_notify_pid;
  		if (!PostmasterMarkPIDForWorkerNotify(rw->rw_worker.bgw_notify_pid))
  		{
  			elog(DEBUG1, "worker notification PID %lu is not valid",
  				 (long) rw->rw_worker.bgw_notify_pid);
  			rw->rw_worker.bgw_notify_pid = 0;
  		}
  
  		/* Initialize postmaster bookkeeping. */
  		rw->rw_backend = NULL;
  		rw->rw_pid = 0;
  		rw->rw_child_slot = 0;
  		rw->rw_crashed_at = 0;
  		rw->rw_shmem_slot = slotno;
  		rw->rw_terminate = false;
  
  		/* Log it! */
  		ereport(DEBUG1,
  				(errmsg("registering background worker \"%s\"",
  						rw->rw_worker.bgw_name)));
  
  		slist_push_head(&BackgroundWorkerList, &rw->rw_lnode);
  	}
  }
  
  /*
   * Forget about a background worker that's no longer needed.
   *
   * The worker must be identified by passing an slist_mutable_iter that
   * points to it.  This convention allows deletion of workers during
   * searches of the worker list, and saves having to search the list again.
   *
   * This function must be invoked only in the postmaster.
   */
  void
  ForgetBackgroundWorker(slist_mutable_iter *cur)
  {
  	RegisteredBgWorker *rw;
  	BackgroundWorkerSlot *slot;
  
  	rw = slist_container(RegisteredBgWorker, rw_lnode, cur->cur);
  
  	Assert(rw->rw_shmem_slot < max_worker_processes);
  	slot = &BackgroundWorkerData->slot[rw->rw_shmem_slot];
  	if ((rw->rw_worker.bgw_flags & BGWORKER_CLASS_PARALLEL) != 0)
  		BackgroundWorkerData->parallel_terminate_count++;
  
  	slot->in_use = false;
  
  	ereport(DEBUG1,
  			(errmsg("unregistering background worker \"%s\"",
  					rw->rw_worker.bgw_name)));
  
  	slist_delete_current(cur);
  	free(rw);
  }
  
  /*
   * Report the PID of a newly-launched background worker in shared memory.
   *
   * This function should only be called from the postmaster.
   */
  void
  ReportBackgroundWorkerPID(RegisteredBgWorker *rw)
  {
  	BackgroundWorkerSlot *slot;
  
  	Assert(rw->rw_shmem_slot < max_worker_processes);
  	slot = &BackgroundWorkerData->slot[rw->rw_shmem_slot];
  	slot->pid = rw->rw_pid;
  
  	if (rw->rw_worker.bgw_notify_pid != 0)
  		kill(rw->rw_worker.bgw_notify_pid, SIGUSR1);
  }
  
  /*
   * Cancel SIGUSR1 notifications for a PID belonging to an exiting backend.
   *
   * This function should only be called from the postmaster.
   */
  void
  BackgroundWorkerStopNotifications(pid_t pid)
  {
  	slist_iter	siter;
  
  	slist_foreach(siter, &BackgroundWorkerList)
  	{
  		RegisteredBgWorker *rw;
  
  		rw = slist_container(RegisteredBgWorker, rw_lnode, siter.cur);
  		if (rw->rw_worker.bgw_notify_pid == pid)
  			rw->rw_worker.bgw_notify_pid = 0;
  	}
  }
  
  /*
   * Reset background worker crash state.
   *
   * We assume that, after a crash-and-restart cycle, background workers without
   * the never-restart flag should be restarted immediately, instead of waiting
   * for bgw_restart_time to elapse.
   */
  void
  ResetBackgroundWorkerCrashTimes(void)
  {
  	slist_mutable_iter iter;
  
  	slist_foreach_modify(iter, &BackgroundWorkerList)
  	{
  		RegisteredBgWorker *rw;
  
  		rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur);
  
  		/*
  		 * For workers that should not be restarted, we don't want to lose the
  		 * information that they have crashed; otherwise, they would be
  		 * restarted, which is wrong.
  		 */
  		if (rw->rw_worker.bgw_restart_time != BGW_NEVER_RESTART)
  			rw->rw_crashed_at = 0;
  	}
  }
  
  #ifdef EXEC_BACKEND
  /*
   * In EXEC_BACKEND mode, workers use this to retrieve their details from
   * shared memory.
   */
  BackgroundWorker *
  BackgroundWorkerEntry(int slotno)
  {
  	static BackgroundWorker myEntry;
  	BackgroundWorkerSlot *slot;
  
  	Assert(slotno < BackgroundWorkerData->total_slots);
  	slot = &BackgroundWorkerData->slot[slotno];
  	Assert(slot->in_use);
  
  	/* must copy this in case we don't intend to retain shmem access */
  	memcpy(&myEntry, &slot->worker, sizeof myEntry);
  	return &myEntry;
  }
  #endif
  
  /*
   * Complain about the BackgroundWorker definition using error level elevel.
   * Return true if it looks ok, false if not (unless elevel >= ERROR, in
   * which case we won't return at all in the not-OK case).
   */
  static bool
  SanityCheckBackgroundWorker(BackgroundWorker *worker, int elevel)
  {
  	/* sanity check for flags */
  	if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION)
  	{
  		if (!(worker->bgw_flags & BGWORKER_SHMEM_ACCESS))
  		{
  			ereport(elevel,
  					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  					 errmsg("background worker \"%s\": must attach to shared memory in order to request a database connection",
  							worker->bgw_name)));
  			return false;
  		}
  
  		if (worker->bgw_start_time == BgWorkerStart_PostmasterStart)
  		{
  			ereport(elevel,
  					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  					 errmsg("background worker \"%s\": cannot request database access if starting at postmaster start",
  							worker->bgw_name)));
  			return false;
  		}
  
  		/* XXX other checks? */
  	}
  
  	if ((worker->bgw_restart_time < 0 &&
  		 worker->bgw_restart_time != BGW_NEVER_RESTART) ||
  		(worker->bgw_restart_time > USECS_PER_DAY / 1000))
  	{
  		ereport(elevel,
  				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  				 errmsg("background worker \"%s\": invalid restart interval",
  						worker->bgw_name)));
  		return false;
  	}
  
  	return true;
  }
  
  static void
  bgworker_quickdie(SIGNAL_ARGS)
  {
  	sigaddset(&BlockSig, SIGQUIT);		/* prevent nested calls */
  	PG_SETMASK(&BlockSig);
  
  	/*
  	 * We DO NOT want to run proc_exit() callbacks -- we're here because
  	 * shared memory may be corrupted, so we don't want to try to clean up our
  	 * transaction.  Just nail the windows shut and get out of town.  Now that
  	 * there's an atexit callback to prevent third-party code from breaking
  	 * things by calling exit() directly, we have to reset the callbacks
  	 * explicitly to make this work as intended.
  	 */
  	on_exit_reset();
  
  	/*
  	 * Note we do exit(2) not exit(0).  This is to force the postmaster into a
  	 * system reset cycle if some idiot DBA sends a manual SIGQUIT to a random
  	 * backend.  This is necessary precisely because we don't clean up our
  	 * shared memory state.  (The "dead man switch" mechanism in pmsignal.c
  	 * should ensure the postmaster sees this as a crash, too, but no harm in
  	 * being doubly sure.)
  	 */
  	exit(2);
  }
  
  /*
   * Standard SIGTERM handler for background workers
   */
  static void
  bgworker_die(SIGNAL_ARGS)
  {
  	PG_SETMASK(&BlockSig);
  
  	ereport(FATAL,
  			(errcode(ERRCODE_ADMIN_SHUTDOWN),
  			 errmsg("terminating background worker \"%s\" due to administrator command",
  					MyBgworkerEntry->bgw_name)));
  }
  
  /*
   * Standard SIGUSR1 handler for unconnected workers
   *
   * Here, we want to make sure an unconnected worker will at least heed
   * latch activity.
   */
  static void
  bgworker_sigusr1_handler(SIGNAL_ARGS)
  {
  	int			save_errno = errno;
  
  	latch_sigusr1_handler();
  
  	errno = save_errno;
  }
  
  /*
   * Start a new background worker
   *
   * This is the main entry point for background worker, to be called from
   * postmaster.
   */
  void
  StartBackgroundWorker(void)
  {
  	sigjmp_buf	local_sigjmp_buf;
  	char		buf[MAXPGPATH];
  	BackgroundWorker *worker = MyBgworkerEntry;
  	bgworker_main_type entrypt;
  
  	if (worker == NULL)
  		elog(FATAL, "unable to find bgworker entry");
  
  	IsBackgroundWorker = true;
  
  	/* Identify myself via ps */
  	snprintf(buf, MAXPGPATH, "bgworker: %s", worker->bgw_name);
  	init_ps_display(buf, "", "", "");
  
  	/*
  	 * If we're not supposed to have shared memory access, then detach from
  	 * shared memory.  If we didn't request shared memory access, the
  	 * postmaster won't force a cluster-wide restart if we exit unexpectedly,
  	 * so we'd better make sure that we don't mess anything up that would
  	 * require that sort of cleanup.
  	 */
  	if ((worker->bgw_flags & BGWORKER_SHMEM_ACCESS) == 0)
  	{
  		dsm_detach_all();
  		PGSharedMemoryDetach();
  	}
  
  	SetProcessingMode(InitProcessing);
  
  	/* Apply PostAuthDelay */
  	if (PostAuthDelay > 0)
  		pg_usleep(PostAuthDelay * 1000000L);
  
  	/*
  	 * Set up signal handlers.
  	 */
  	if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION)
  	{
  		/*
  		 * SIGINT is used to signal canceling the current action
  		 */
  		pqsignal(SIGINT, StatementCancelHandler);
  		pqsignal(SIGUSR1, procsignal_sigusr1_handler);
  		pqsignal(SIGFPE, FloatExceptionHandler);
  
  		/* XXX Any other handlers needed here? */
  	}
  	else
  	{
  		pqsignal(SIGINT, SIG_IGN);
  		pqsignal(SIGUSR1, bgworker_sigusr1_handler);
  		pqsignal(SIGFPE, SIG_IGN);
  	}
  	pqsignal(SIGTERM, bgworker_die);
  	pqsignal(SIGHUP, SIG_IGN);
  
  	pqsignal(SIGQUIT, bgworker_quickdie);
  	InitializeTimeouts();		/* establishes SIGALRM handler */
  
  	pqsignal(SIGPIPE, SIG_IGN);
  	pqsignal(SIGUSR2, SIG_IGN);
  	pqsignal(SIGCHLD, SIG_DFL);
  
  	/*
  	 * If an exception is encountered, processing resumes here.
  	 *
  	 * See notes in postgres.c about the design of this coding.
  	 */
  	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
  	{
  		/* Since not using PG_TRY, must reset error stack by hand */
  		error_context_stack = NULL;
  
  		/* Prevent interrupts while cleaning up */
  		HOLD_INTERRUPTS();
  
  		/* Report the error to the server log */
  		EmitErrorReport();
  
  		/*
  		 * Do we need more cleanup here?  For shmem-connected bgworkers, we
  		 * will call InitProcess below, which will install ProcKill as exit
  		 * callback.  That will take care of releasing locks, etc.
  		 */
  
  		/* and go away */
  		proc_exit(1);
  	}
  
  	/* We can now handle ereport(ERROR) */
  	PG_exception_stack = &local_sigjmp_buf;
  
  	/*
  	 * If the background worker request shared memory access, set that up now;
  	 * else, detach all shared memory segments.
  	 */
  	if (worker->bgw_flags & BGWORKER_SHMEM_ACCESS)
  	{
  		/*
  		 * Early initialization.  Some of this could be useful even for
  		 * background workers that aren't using shared memory, but they can
  		 * call the individual startup routines for those subsystems if
  		 * needed.
  		 */
  		BaseInit();
  
  		/*
  		 * Create a per-backend PGPROC struct in shared memory, except in the
  		 * EXEC_BACKEND case where this was done in SubPostmasterMain. We must
  		 * do this before we can use LWLocks (and in the EXEC_BACKEND case we
  		 * already had to do some stuff with LWLocks).
  		 */
  #ifndef EXEC_BACKEND
  		InitProcess();
  #endif
  	}
  
  	/*
  	 * If bgw_main is set, we use that value as the initial entrypoint.
  	 * However, if the library containing the entrypoint wasn't loaded at
  	 * postmaster startup time, passing it as a direct function pointer is not
  	 * possible.  To work around that, we allow callers for whom a function
  	 * pointer is not available to pass a library name (which will be loaded,
  	 * if necessary) and a function name (which will be looked up in the named
  	 * library).
  	 */
  	if (worker->bgw_main != NULL)
  		entrypt = worker->bgw_main;
  	else
  		entrypt = (bgworker_main_type)
  			load_external_function(worker->bgw_library_name,
  								   worker->bgw_function_name,
  								   true, NULL);
  
  	/*
  	 * Note that in normal processes, we would call InitPostgres here.  For a
  	 * worker, however, we don't know what database to connect to, yet; so we
  	 * need to wait until the user code does it via
  	 * BackgroundWorkerInitializeConnection().
  	 */
  
  	/*
  	 * Now invoke the user-defined worker code
  	 */
  	entrypt(worker->bgw_main_arg);
  
  	/* ... and if it returns, we're done */
  	proc_exit(0);
  }
  
  /*
   * Register a new background worker while processing shared_preload_libraries.
   *
   * This can only be called in the _PG_init function of a module library
   * that's loaded by shared_preload_libraries; otherwise it has no effect.
   */
  void
  RegisterBackgroundWorker(BackgroundWorker *worker)
  {
  	RegisteredBgWorker *rw;
  	static int	numworkers = 0;
  	bool		internal = false;
  	int			i;
  
  	if (!IsUnderPostmaster)
  		ereport(DEBUG1,
  		 (errmsg("registering background worker \"%s\"", worker->bgw_name)));
  
  	for (i = 0; InternalBGWorkers[i]; i++)
  	{
  		if (worker->bgw_main == InternalBGWorkers[i])
  		{
  			internal = true;
  			break;
  		}
  	}
  
  	if (!process_shared_preload_libraries_in_progress && !internal)
  	{
  		if (!IsUnderPostmaster)
  			ereport(LOG,
  					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  					 errmsg("background worker \"%s\": must be registered in shared_preload_libraries",
  							worker->bgw_name)));
  		return;
  	}
  
  	if (!SanityCheckBackgroundWorker(worker, LOG))
  		return;
  
  	if (worker->bgw_notify_pid != 0)
  	{
  		ereport(LOG,
  				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  				 errmsg("background worker \"%s\": only dynamic background workers can request notification",
  						worker->bgw_name)));
  		return;
  	}
  
  	/*
  	 * Enforce maximum number of workers.  Note this is overly restrictive: we
  	 * could allow more non-shmem-connected workers, because these don't count
  	 * towards the MAX_BACKENDS limit elsewhere.  For now, it doesn't seem
  	 * important to relax this restriction.
  	 */
  	if (++numworkers > max_worker_processes)
  	{
  		ereport(LOG,
  				(errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
  				 errmsg("too many background workers"),
  				 errdetail_plural("Up to %d background worker can be registered with the current settings.",
  								  "Up to %d background workers can be registered with the current settings.",
  								  max_worker_processes,
  								  max_worker_processes),
  				 errhint("Consider increasing the configuration parameter \"max_worker_processes\".")));
  		return;
  	}
  
  	/*
  	 * Copy the registration data into the registered workers list.
  	 */
  	rw = malloc(sizeof(RegisteredBgWorker));
  	if (rw == NULL)
  	{
  		ereport(LOG,
  				(errcode(ERRCODE_OUT_OF_MEMORY),
  				 errmsg("out of memory")));
  		return;
  	}
  
  	rw->rw_worker = *worker;
  	rw->rw_backend = NULL;
  	rw->rw_pid = 0;
  	rw->rw_child_slot = 0;
  	rw->rw_crashed_at = 0;
  	rw->rw_terminate = false;
  
  	slist_push_head(&BackgroundWorkerList, &rw->rw_lnode);
  }
  
  /*
   * Register a new background worker from a regular backend.
   *
   * Returns true on success and false on failure.  Failure typically indicates
   * that no background worker slots are currently available.
   *
   * If handle != NULL, we'll set *handle to a pointer that can subsequently
   * be used as an argument to GetBackgroundWorkerPid().  The caller can
   * free this pointer using pfree(), if desired.
   */
  bool
  RegisterDynamicBackgroundWorker(BackgroundWorker *worker,
  								BackgroundWorkerHandle **handle)
  {
  	int			slotno;
  	bool		success = false;
  	bool		parallel;
  	uint64		generation = 0;
  
  	/*
  	 * We can't register dynamic background workers from the postmaster. If
  	 * this is a standalone backend, we're the only process and can't start
  	 * any more.  In a multi-process environment, it might be theoretically
  	 * possible, but we don't currently support it due to locking
  	 * considerations; see comments on the BackgroundWorkerSlot data
  	 * structure.
  	 */
  	if (!IsUnderPostmaster)
  		return false;
  
  	if (!SanityCheckBackgroundWorker(worker, ERROR))
  		return false;
  
  	parallel = (worker->bgw_flags & BGWORKER_CLASS_PARALLEL) != 0;
  
  	LWLockAcquire(BackgroundWorkerLock, LW_EXCLUSIVE);
  
  	/*
  	 * If this is a parallel worker, check whether there are already too many
  	 * parallel workers; if so, don't register another one.  Our view of
  	 * parallel_terminate_count may be slightly stale, but that doesn't really
  	 * matter: we would have gotten the same result if we'd arrived here
  	 * slightly earlier anyway.  There's no help for it, either, since the
  	 * postmaster must not take locks; a memory barrier wouldn't guarantee
  	 * anything useful.
  	 */
  	if (parallel && (BackgroundWorkerData->parallel_register_count -
  					 BackgroundWorkerData->parallel_terminate_count) >=
  		max_parallel_workers)
  	{
  		LWLockRelease(BackgroundWorkerLock);
  		return false;
  	}
  
  	/*
  	 * Look for an unused slot.  If we find one, grab it.
  	 */
  	for (slotno = 0; slotno < BackgroundWorkerData->total_slots; ++slotno)
  	{
  		BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno];
  
  		if (!slot->in_use)
  		{
  			memcpy(&slot->worker, worker, sizeof(BackgroundWorker));
  			slot->pid = InvalidPid;		/* indicates not started yet */
  			slot->generation++;
  			slot->terminate = false;
  			generation = slot->generation;
  			if (parallel)
  				BackgroundWorkerData->parallel_register_count++;
  
  			/*
  			 * Make sure postmaster doesn't see the slot as in use before it
  			 * sees the new contents.
  			 */
  			pg_write_barrier();
  
  			slot->in_use = true;
  			success = true;
  			break;
  		}
  	}
  
  	LWLockRelease(BackgroundWorkerLock);
  
  	/* If we found a slot, tell the postmaster to notice the change. */
  	if (success)
  		SendPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE);
  
  	/*
  	 * If we found a slot and the user has provided a handle, initialize it.
  	 */
  	if (success && handle)
  	{
  		*handle = palloc(sizeof(BackgroundWorkerHandle));
  		(*handle)->slot = slotno;
  		(*handle)->generation = generation;
  	}
  
  	return success;
  }
  
  /*
   * Get the PID of a dynamically-registered background worker.
   *
   * If the worker is determined to be running, the return value will be
   * BGWH_STARTED and *pidp will get the PID of the worker process.
   * Otherwise, the return value will be BGWH_NOT_YET_STARTED if the worker
   * hasn't been started yet, and BGWH_STOPPED if the worker was previously
   * running but is no longer.
   *
   * In the latter case, the worker may be stopped temporarily (if it is
   * configured for automatic restart and exited non-zero) or gone for
   * good (if it exited with code 0 or if it is configured not to restart).
   */
  BgwHandleStatus
  GetBackgroundWorkerPid(BackgroundWorkerHandle *handle, pid_t *pidp)
  {
  	BackgroundWorkerSlot *slot;
  	pid_t		pid;
  
  	Assert(handle->slot < max_worker_processes);
  	slot = &BackgroundWorkerData->slot[handle->slot];
  
  	/*
  	 * We could probably arrange to synchronize access to data using memory
  	 * barriers only, but for now, let's just keep it simple and grab the
  	 * lock.  It seems unlikely that there will be enough traffic here to
  	 * result in meaningful contention.
  	 */
  	LWLockAcquire(BackgroundWorkerLock, LW_SHARED);
  
  	/*
  	 * The generation number can't be concurrently changed while we hold the
  	 * lock.  The pid, which is updated by the postmaster, can change at any
  	 * time, but we assume such changes are atomic.  So the value we read
  	 * won't be garbage, but it might be out of date by the time the caller
  	 * examines it (but that's unavoidable anyway).
  	 */
  	if (handle->generation != slot->generation)
  		pid = 0;
  	else
  		pid = slot->pid;
  
  	/* All done. */
  	LWLockRelease(BackgroundWorkerLock);
  
  	if (pid == 0)
  		return BGWH_STOPPED;
  	else if (pid == InvalidPid)
  		return BGWH_NOT_YET_STARTED;
  	*pidp = pid;
  	return BGWH_STARTED;
  }
  
  /*
   * Wait for a background worker to start up.
   *
   * This is like GetBackgroundWorkerPid(), except that if the worker has not
   * yet started, we wait for it to do so; thus, BGWH_NOT_YET_STARTED is never
   * returned.  However, if the postmaster has died, we give up and return
   * BGWH_POSTMASTER_DIED, since it that case we know that startup will not
   * take place.
   */
  BgwHandleStatus
  WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp)
  {
  	BgwHandleStatus status;
  	int			rc;
  
  	for (;;)
  	{
  		pid_t		pid;
  
  		CHECK_FOR_INTERRUPTS();
  
  		status = GetBackgroundWorkerPid(handle, &pid);
  		if (status == BGWH_STARTED)
  			*pidp = pid;
  		if (status != BGWH_NOT_YET_STARTED)
  			break;
  
  		rc = WaitLatch(MyLatch,
  					   WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
  					   WAIT_EVENT_BGWORKER_STARTUP);
  
  		if (rc & WL_POSTMASTER_DEATH)
  		{
  			status = BGWH_POSTMASTER_DIED;
  			break;
  		}
  
  		ResetLatch(MyLatch);
  	}
  
  	return status;
  }
  
  /*
   * Wait for a background worker to stop.
   *
   * If the worker hasn't yet started, or is running, we wait for it to stop
   * and then return BGWH_STOPPED.  However, if the postmaster has died, we give
   * up and return BGWH_POSTMASTER_DIED, because it's the postmaster that
   * notifies us when a worker's state changes.
   */
  BgwHandleStatus
  WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *handle)
  {
  	BgwHandleStatus status;
  	int			rc;
  
  	for (;;)
  	{
  		pid_t		pid;
  
  		CHECK_FOR_INTERRUPTS();
  
  		status = GetBackgroundWorkerPid(handle, &pid);
  		if (status == BGWH_STOPPED)
  			break;
  
  		rc = WaitLatch(&MyProc->procLatch,
  					   WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
  					   WAIT_EVENT_BGWORKER_SHUTDOWN);
  
  		if (rc & WL_POSTMASTER_DEATH)
  		{
  			status = BGWH_POSTMASTER_DIED;
  			break;
  		}
  
  		ResetLatch(&MyProc->procLatch);
  	}
  
  	return status;
  }
  
  /*
   * Instruct the postmaster to terminate a background worker.
   *
   * Note that it's safe to do this without regard to whether the worker is
   * still running, or even if the worker may already have existed and been
   * unregistered.
   */
  void
  TerminateBackgroundWorker(BackgroundWorkerHandle *handle)
  {
  	BackgroundWorkerSlot *slot;
  	bool		signal_postmaster = false;
  
  	Assert(handle->slot < max_worker_processes);
  	slot = &BackgroundWorkerData->slot[handle->slot];
  
  	/* Set terminate flag in shared memory, unless slot has been reused. */
  	LWLockAcquire(BackgroundWorkerLock, LW_EXCLUSIVE);
  	if (handle->generation == slot->generation)
  	{
  		slot->terminate = true;
  		signal_postmaster = true;
  	}
  	LWLockRelease(BackgroundWorkerLock);
  
  	/* Make sure the postmaster notices the change to shared memory. */
  	if (signal_postmaster)
  		SendPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE);
  }
  