On Sat, Dec 3, 2022 at 10:41 AM Thomas Munro <thomas.mu...@gmail.com> wrote: > Here's an iteration like that. Still WIP grade. It passes, but there > must be something I don't understand about this computer program yet, > because if I move the "if (pending_..." section up into the block > where WL_LATCH_SET has arrived (instead of testing those variables > every time through the loop), a couple of tests leave zombie > (unreaped) processes behind, indicating that something funky happened > to the state machine that I haven't yet grokked. Will look more next > week.
Duh. The reason for that was the pre-existing special case for PM_WAIT_DEAD_END, which used a sleep(100ms) loop to wait for children to exit, which I needed to change to a latch wait. Fixed in the next iteration, attached. The reason for the existing sleep-based approach was that we didn't want to accept any more connections (or spin furiously because the listen queue was non-empty). So in this version I invented a way to suppress socket events temporarily with WL_SOCKET_IGNORE, and then reactivate them after crash reinit. Still WIP, but I hope travelling in the right direction.
From 65b5fa1f7024cb78cee9ba57d36a78dc17ffe492 Mon Sep 17 00:00:00 2001 From: Thomas Munro <thomas.mu...@gmail.com> Date: Wed, 9 Nov 2022 22:59:58 +1300 Subject: [PATCH v3] Give the postmaster a WaitEventSet and a latch. Traditionally, the postmaster's architecture was quite unusual. It did a lot of work inside signal handlers, which were only unblocked while waiting in select() to make that safe. Switch to a more typical architecture, where signal handlers just set flags and use a latch to close races. Now the postmaster looks like all other PostgreSQL processes, multiplexing its event processing in epoll_wait()/kevent()/poll()/WaitForMultipleObjects() depending on the OS. Changes: * WL_SOCKET_ACCEPT is a new event for an incoming connection (on Unix, this is just another name for WL_SOCKET_READABLE, but Window has a different underlying event; this mirrors WL_SOCKET_CONNECTED on the other end of a connection) * WL_SOCKET_IGNORE is a new way to stop waking up for new incoming connections while shutting down. * Small adjustments to WaitEventSet to allow running in the postmaster. * Allow the postmaster to set up its own local latch. For now we don't want other backends setting the postmaster's latch directly (perhaps later we'll figure out how to use a shared latch "robustly", so that memory corruption can't interfere with the postmaster's cleanup-and-restart responsibilities, but for now there is a two-step signal protocol SIGUSR1 -> SIGURG). * The existing signal handlers are cut in two: a handle_XXX part that sets a pending_XXX variable and sets the local latch, and a process_XXX part. * ServerLoop(), the process_XXX() functions and PostmasterStateMachine() now all take a pointer to a Postmaster object that lives on the stack as a parameter that initially holds the WaitEventSet they need to do their job. Many other global variables could be moved into it, but that's not done here. * Signal handlers are now installed with the regular pqsignal() function rather then the special pqsignal_pm() function; the concerns about the portability of SA_RESTART vs select() are no longer relevant: SUSv2 left it implementation-defined whether select() restarts, but didn't add that qualification for poll(), and it doesn't matter anyway because we call SetLatch() creating a new reason to wake up. Reviewed-by: Andres Freund <and...@anarazel.de> Discussion: https://postgr.es/m/CA%2BhUKG%2BZ-HpOj1JsO9eWUP%2Bar7npSVinsC_npxSy%2BjdOMsx%3DGg%40mail.gmail.com --- src/backend/libpq/pqsignal.c | 40 --- src/backend/postmaster/postmaster.c | 413 +++++++++++++++------------- src/backend/storage/ipc/latch.c | 22 ++ src/backend/tcop/postgres.c | 1 - src/backend/utils/init/miscinit.c | 13 +- src/include/libpq/pqsignal.h | 3 - src/include/miscadmin.h | 1 + src/include/storage/latch.h | 9 +- 8 files changed, 266 insertions(+), 236 deletions(-) diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c index 1ab34c5214..718043a39d 100644 --- a/src/backend/libpq/pqsignal.c +++ b/src/backend/libpq/pqsignal.c @@ -97,43 +97,3 @@ pqinitmask(void) sigdelset(&StartupBlockSig, SIGALRM); #endif } - -/* - * Set up a postmaster signal handler for signal "signo" - * - * Returns the previous handler. - * - * This is used only in the postmaster, which has its own odd approach to - * signal handling. For signals with handlers, we block all signals for the - * duration of signal handler execution. We also do not set the SA_RESTART - * flag; this should be safe given the tiny range of code in which the - * postmaster ever unblocks signals. - * - * pqinitmask() must have been invoked previously. - */ -pqsigfunc -pqsignal_pm(int signo, pqsigfunc func) -{ - struct sigaction act, - oact; - - act.sa_handler = func; - if (func == SIG_IGN || func == SIG_DFL) - { - /* in these cases, act the same as pqsignal() */ - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - } - else - { - act.sa_mask = BlockSig; - act.sa_flags = 0; - } -#ifdef SA_NOCLDSTOP - if (signo == SIGCHLD) - act.sa_flags |= SA_NOCLDSTOP; -#endif - if (sigaction(signo, &act, &oact) < 0) - return SIG_ERR; - return oact.sa_handler; -} diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index a8a246921f..5000fb987d 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -70,7 +70,6 @@ #include <time.h> #include <sys/wait.h> #include <ctype.h> -#include <sys/select.h> #include <sys/stat.h> #include <sys/socket.h> #include <fcntl.h> @@ -325,6 +324,16 @@ typedef enum PM_NO_CHILDREN /* all important children have exited */ } PMState; +/* + * Object representing the state of a postmaster. + * + * XXX Lots of global variables could move in here. + */ +typedef struct +{ + WaitEventSet *wes; +} Postmaster; + static PMState pmState = PM_INIT; /* @@ -362,6 +371,14 @@ static volatile sig_atomic_t WalReceiverRequested = false; static volatile bool StartWorkerNeeded = true; static volatile bool HaveCrashedWorker = false; +/* set when signals arrive */ +static volatile sig_atomic_t pending_action_request; +static volatile sig_atomic_t pending_child_exit; +static volatile sig_atomic_t pending_reload_request; +static volatile sig_atomic_t pending_shutdown_request; + +static bool reenable_server_socket_events; + #ifdef USE_SSL /* Set when and if SSL has been initialized properly */ static bool LoadedSSL = false; @@ -380,10 +397,14 @@ static void getInstallationPaths(const char *argv0); static void checkControlFile(void); static Port *ConnCreate(int serverFd); static void ConnFree(Port *port); -static void SIGHUP_handler(SIGNAL_ARGS); -static void pmdie(SIGNAL_ARGS); -static void reaper(SIGNAL_ARGS); -static void sigusr1_handler(SIGNAL_ARGS); +static void handle_action_request_signal(SIGNAL_ARGS); +static void handle_child_exit_signal(SIGNAL_ARGS); +static void handle_reload_request_signal(SIGNAL_ARGS); +static void handle_shutdown_request_signal(SIGNAL_ARGS); +static void process_action_request(Postmaster *postmaster); +static void process_child_exit(Postmaster *postmaster); +static void process_reload_request(void); +static void process_shutdown_request(Postmaster *postmaster); static void process_startup_packet_die(SIGNAL_ARGS); static void dummy_handler(SIGNAL_ARGS); static void StartupPacketTimeoutHandler(void); @@ -392,16 +413,15 @@ static bool CleanupBackgroundWorker(int pid, int exitstatus); static void HandleChildCrash(int pid, int exitstatus, const char *procname); static void LogChildExit(int lev, const char *procname, int pid, int exitstatus); -static void PostmasterStateMachine(void); +static void PostmasterStateMachine(Postmaster *postmaster); static void BackendInitialize(Port *port); static void BackendRun(Port *port) pg_attribute_noreturn(); static void ExitPostmaster(int status) pg_attribute_noreturn(); -static int ServerLoop(void); +static int ServerLoop(Postmaster *postmaster); static int BackendStartup(Port *port); static int ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done); static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options); static void processCancelRequest(Port *port, void *pkt); -static int initMasks(fd_set *rmask); static void report_fork_failure_to_client(Port *port, int errnum); static CAC_state canAcceptConnections(int backend_type); static bool RandomCancelKey(int32 *cancel_key); @@ -568,6 +588,7 @@ PostmasterMain(int argc, char *argv[]) bool listen_addr_saved = false; int i; char *output_config_variable = NULL; + Postmaster postmaster = {0}; InitProcessGlobals(); @@ -609,26 +630,6 @@ PostmasterMain(int argc, char *argv[]) /* * Set up signal handlers for the postmaster process. * - * In the postmaster, we use pqsignal_pm() rather than pqsignal() (which - * is used by all child processes and client processes). That has a - * couple of special behaviors: - * - * 1. We tell sigaction() to block all signals for the duration of the - * signal handler. This is faster than our old approach of - * blocking/unblocking explicitly in the signal handler, and it should also - * prevent excessive stack consumption if signals arrive quickly. - * - * 2. We do not set the SA_RESTART flag. This is because signals will be - * blocked at all times except when ServerLoop is waiting for something to - * happen, and during that window, we want signals to exit the select(2) - * wait so that ServerLoop can respond if anything interesting happened. - * On some platforms, signals marked SA_RESTART would not cause the - * select() wait to end. - * - * Child processes will generally want SA_RESTART, so pqsignal() sets that - * flag. We expect children to set up their own handlers before - * unblocking signals. - * * CAUTION: when changing this list, check for side-effects on the signal * handling setup of child processes. See tcop/postgres.c, * bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/walwriter.c, @@ -638,26 +639,21 @@ PostmasterMain(int argc, char *argv[]) pqinitmask(); PG_SETMASK(&BlockSig); - pqsignal_pm(SIGHUP, SIGHUP_handler); /* reread config file and have - * children do same */ - pqsignal_pm(SIGINT, pmdie); /* send SIGTERM and shut down */ - pqsignal_pm(SIGQUIT, pmdie); /* send SIGQUIT and die */ - pqsignal_pm(SIGTERM, pmdie); /* wait for children and shut down */ - pqsignal_pm(SIGALRM, SIG_IGN); /* ignored */ - pqsignal_pm(SIGPIPE, SIG_IGN); /* ignored */ - pqsignal_pm(SIGUSR1, sigusr1_handler); /* message from child process */ - pqsignal_pm(SIGUSR2, dummy_handler); /* unused, reserve for children */ - pqsignal_pm(SIGCHLD, reaper); /* handle child termination */ + pqsignal(SIGHUP, handle_reload_request_signal); + pqsignal(SIGINT, handle_shutdown_request_signal); + pqsignal(SIGQUIT, handle_shutdown_request_signal); + pqsignal(SIGTERM, handle_shutdown_request_signal); + pqsignal(SIGALRM, SIG_IGN); /* ignored */ + pqsignal(SIGPIPE, SIG_IGN); /* ignored */ + pqsignal(SIGUSR1, handle_action_request_signal); + pqsignal(SIGUSR2, dummy_handler); /* unused, reserve for children */ + pqsignal(SIGCHLD, handle_child_exit_signal); -#ifdef SIGURG + /* This may configure SIGURG, depending on platform. */ + InitializeLatchSupport(); + InitLocalLatch(); - /* - * Ignore SIGURG for now. Child processes may change this (see - * InitializeLatchSupport), but they will not receive any such signals - * until they wait on a latch. - */ - pqsignal_pm(SIGURG, SIG_IGN); /* ignored */ -#endif + PG_SETMASK(&UnBlockSig); /* * No other place in Postgres should touch SIGTTIN/SIGTTOU handling. We @@ -667,15 +663,15 @@ PostmasterMain(int argc, char *argv[]) * child processes should just allow the inherited settings to stand. */ #ifdef SIGTTIN - pqsignal_pm(SIGTTIN, SIG_IGN); /* ignored */ + pqsignal(SIGTTIN, SIG_IGN); /* ignored */ #endif #ifdef SIGTTOU - pqsignal_pm(SIGTTOU, SIG_IGN); /* ignored */ + pqsignal(SIGTTOU, SIG_IGN); /* ignored */ #endif /* ignore SIGXFSZ, so that ulimit violations work like disk full */ #ifdef SIGXFSZ - pqsignal_pm(SIGXFSZ, SIG_IGN); /* ignored */ + pqsignal(SIGXFSZ, SIG_IGN); /* ignored */ #endif /* @@ -1460,7 +1456,7 @@ PostmasterMain(int argc, char *argv[]) /* Some workers may be scheduled to start now */ maybe_start_bgworkers(); - status = ServerLoop(); + status = ServerLoop(&postmaster); /* * ServerLoop probably shouldn't ever return, but if it does, close down. @@ -1698,105 +1694,112 @@ DetermineSleepTime(struct timeval *timeout) } } +/* + * Initialize the WaitEventSet we'll use in our main event loop. + */ +static void +InitializeWaitSet(Postmaster *postmaster) +{ + /* Set up a WaitEventSet for our latch and listening sockets. */ + postmaster->wes = CreateWaitEventSet(CurrentMemoryContext, 1 + MAXLISTEN); + AddWaitEventToSet(postmaster->wes, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch, NULL); + for (int i = 0; i < MAXLISTEN; i++) + { + int fd = ListenSocket[i]; + + if (fd == PGINVALID_SOCKET) + break; + AddWaitEventToSet(postmaster->wes, WL_SOCKET_ACCEPT, fd, NULL, NULL); + } +} + +/* + * Activate or deactivate the server socket events. + */ +static void +AdjustServerSocketEvents(Postmaster *postmaster, bool active) +{ + for (int pos = 1; pos < GetNumRegisteredWaitEvents(postmaster->wes); ++pos) + ModifyWaitEvent(postmaster->wes, + pos, active ? WL_SOCKET_ACCEPT : WL_SOCKET_IGNORE, + NULL); +} + /* * Main idle loop of postmaster * * NB: Needs to be called with signals blocked */ static int -ServerLoop(void) +ServerLoop(Postmaster *postmaster) { - fd_set readmask; - int nSockets; time_t last_lockfile_recheck_time, last_touch_time; + WaitEvent events[MAXLISTEN]; + int nevents; + InitializeWaitSet(postmaster); last_lockfile_recheck_time = last_touch_time = time(NULL); - nSockets = initMasks(&readmask); - for (;;) { - fd_set rmask; - int selres; time_t now; + struct timeval timeout; - /* - * Wait for a connection request to arrive. - * - * We block all signals except while sleeping. That makes it safe for - * signal handlers, which again block all signals while executing, to - * do nontrivial work. - * - * If we are in PM_WAIT_DEAD_END state, then we don't want to accept - * any new connections, so we don't call select(), and just sleep. - */ - memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set)); - - if (pmState == PM_WAIT_DEAD_END) - { - PG_SETMASK(&UnBlockSig); - - pg_usleep(100000L); /* 100 msec seems reasonable */ - selres = 0; - - PG_SETMASK(&BlockSig); - } - else - { - /* must set timeout each time; some OSes change it! */ - struct timeval timeout; - - /* Needs to run with blocked signals! */ - DetermineSleepTime(&timeout); - - PG_SETMASK(&UnBlockSig); + DetermineSleepTime(&timeout); - selres = select(nSockets, &rmask, NULL, NULL, &timeout); + nevents = WaitEventSetWait(postmaster->wes, + timeout.tv_sec * 1000 + timeout.tv_usec / 1000, + events, + lengthof(events), + 0 /* postmaster posts no wait_events */); - PG_SETMASK(&BlockSig); - } - - /* Now check the select() result */ - if (selres < 0) + /* + * Latch set by signal handler, or new connection pending on any of our + * sockets? If the latter, fork a child process to deal with it. + */ + for (int i = 0; i < nevents; i++) { - if (errno != EINTR && errno != EWOULDBLOCK) + if (events[i].events & WL_LATCH_SET) { - ereport(LOG, - (errcode_for_socket_access(), - errmsg("select() failed in postmaster: %m"))); - return STATUS_ERROR; + ResetLatch(MyLatch); + + /* Process work scheduled by signal handlers. */ + if (pending_action_request) + process_action_request(postmaster); + if (pending_child_exit) + process_child_exit(postmaster); + if (pending_reload_request) + process_reload_request(); + if (pending_shutdown_request) + process_shutdown_request(postmaster); } - } + else if (events[i].events & WL_SOCKET_ACCEPT) + { + Port *port; - /* - * New connection pending on any of our sockets? If so, fork a child - * process to deal with it. - */ - if (selres > 0) - { - int i; + /* + * If we are in PM_WAIT_DEAD_END state, then we don't want to + * accept any new connections. Lazily silence all socket + * events. + */ + if (pmState == PM_WAIT_DEAD_END) + { + AdjustServerSocketEvents(postmaster, false); + continue; + } - for (i = 0; i < MAXLISTEN; i++) - { - if (ListenSocket[i] == PGINVALID_SOCKET) - break; - if (FD_ISSET(ListenSocket[i], &rmask)) + port = ConnCreate(events[i].fd); + if (port) { - Port *port; + BackendStartup(port); - port = ConnCreate(ListenSocket[i]); - if (port) - { - BackendStartup(port); - - /* - * We no longer need the open socket or port structure - * in this process - */ - StreamClose(port->sock); - ConnFree(port); - } + /* + * We no longer need the open socket or port structure + * in this process + */ + StreamClose(port->sock); + ConnFree(port); } } } @@ -1939,34 +1942,6 @@ ServerLoop(void) } } -/* - * Initialise the masks for select() for the ports we are listening on. - * Return the number of sockets to listen on. - */ -static int -initMasks(fd_set *rmask) -{ - int maxsock = -1; - int i; - - FD_ZERO(rmask); - - for (i = 0; i < MAXLISTEN; i++) - { - int fd = ListenSocket[i]; - - if (fd == PGINVALID_SOCKET) - break; - FD_SET(fd, rmask); - - if (fd > maxsock) - maxsock = fd; - } - - return maxsock + 1; -} - - /* * Read a client's startup packet and do something according to it. * @@ -2707,14 +2682,42 @@ InitProcessGlobals(void) #endif } +/* + * Child processes use SIGUSR1 to for pmsignals. pg_ctl uses SIGUSR1 to ask + * postmaster to check for logrotate and promote files. + */ +static void +handle_action_request_signal(SIGNAL_ARGS) +{ + int save_errno = errno; + + pending_action_request = true; + SetLatch(MyLatch); + + errno = save_errno; +} + +/* + * pg_ctl uses SIGHUP to request a reload of the configuration files. + */ +static void +handle_reload_request_signal(SIGNAL_ARGS) +{ + int save_errno = errno; + + pending_reload_request = true; + SetLatch(MyLatch); + + errno = save_errno; +} /* - * SIGHUP -- reread config files, and tell children to do same + * Re-read config files, and tell children to do same. */ static void -SIGHUP_handler(SIGNAL_ARGS) +process_reload_request(void) { - int save_errno = errno; + pending_reload_request = false; if (Shutdown <= SmartShutdown) { @@ -2771,27 +2774,47 @@ SIGHUP_handler(SIGNAL_ARGS) write_nondefault_variables(PGC_SIGHUP); #endif } - - errno = save_errno; } - /* - * pmdie -- signal handler for processing various postmaster signals. + * pg_ctl uses SIGTERM, SIGINT and SIGQUIT to request different types of + * shutdown. */ static void -pmdie(SIGNAL_ARGS) +handle_shutdown_request_signal(SIGNAL_ARGS) { - int save_errno = errno; - - ereport(DEBUG2, - (errmsg_internal("postmaster received signal %d", - postgres_signal_arg))); + int save_errno = errno; switch (postgres_signal_arg) { case SIGTERM: + pending_shutdown_request = SmartShutdown; + break; + case SIGINT: + pending_shutdown_request = FastShutdown; + break; + case SIGQUIT: + pending_shutdown_request = ImmediateShutdown; + break; + } + SetLatch(MyLatch); + + errno = save_errno; +} +/* + * Process shutdown request. + */ +static void +process_shutdown_request(Postmaster *postmaster) +{ + int mode = pending_shutdown_request; + + pending_shutdown_request = NoShutdown; + + switch (mode) + { + case SmartShutdown: /* * Smart Shutdown: * @@ -2827,11 +2850,10 @@ pmdie(SIGNAL_ARGS) * that is already the case, PostmasterStateMachine will take the * next step. */ - PostmasterStateMachine(); + PostmasterStateMachine(postmaster); break; - case SIGINT: - + case FastShutdown: /* * Fast Shutdown: * @@ -2868,11 +2890,10 @@ pmdie(SIGNAL_ARGS) * PostmasterStateMachine will issue any necessary signals, or * take the next step if no child processes need to be killed. */ - PostmasterStateMachine(); + PostmasterStateMachine(postmaster); break; - case SIGQUIT: - + case ImmediateShutdown: /* * Immediate Shutdown: * @@ -2905,23 +2926,33 @@ pmdie(SIGNAL_ARGS) * Now wait for backends to exit. If there are none, * PostmasterStateMachine will take the next step. */ - PostmasterStateMachine(); + PostmasterStateMachine(postmaster); break; } +} + +static void +handle_child_exit_signal(SIGNAL_ARGS) +{ + int save_errno = errno; + + pending_child_exit = true; + SetLatch(MyLatch); errno = save_errno; } /* - * Reaper -- signal handler to cleanup after a child process dies. + * Cleanup after a child process dies. */ static void -reaper(SIGNAL_ARGS) +process_child_exit(Postmaster *postmaster) { - int save_errno = errno; int pid; /* process id of dead child process */ int exitstatus; /* its exit status */ + pending_child_exit = false; + ereport(DEBUG4, (errmsg_internal("reaping dead processes"))); @@ -3212,9 +3243,7 @@ reaper(SIGNAL_ARGS) * After cleaning out the SIGCHLD queue, see if we have any state changes * or actions to make. */ - PostmasterStateMachine(); - - errno = save_errno; + PostmasterStateMachine(postmaster); } /* @@ -3642,11 +3671,12 @@ LogChildExit(int lev, const char *procname, int pid, int exitstatus) /* * Advance the postmaster's state machine and take actions as appropriate * - * This is common code for pmdie(), reaper() and sigusr1_handler(), which - * receive the signals that might mean we need to change state. + * This is common code for process_shutdown_request(), process_child_exit() and + * process_action_request(), which process the signals that might mean we need + * to change state. */ static void -PostmasterStateMachine(void) +PostmasterStateMachine(Postmaster *postmaster) { /* If we're doing a smart shutdown, try to advance that state. */ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY) @@ -3819,6 +3849,9 @@ PostmasterStateMachine(void) Assert(AutoVacPID == 0); /* syslogger is not considered here */ pmState = PM_NO_CHILDREN; + + /* re-activate server socket events */ + AdjustServerSocketEvents(postmaster, true); } } @@ -3905,6 +3938,9 @@ PostmasterStateMachine(void) pmState = PM_STARTUP; /* crash recovery started, reset SIGKILL flag */ AbortStartTime = 0; + + /* start accepting server socket connection events again */ + reenable_server_socket_events = true; } } @@ -4094,6 +4130,7 @@ BackendStartup(Port *port) /* Hasn't asked to be notified about any bgworkers yet */ bn->bgworker_notify = false; + PG_SETMASK(&BlockSig); #ifdef EXEC_BACKEND pid = backend_forkexec(port); #else /* !EXEC_BACKEND */ @@ -4124,6 +4161,7 @@ BackendStartup(Port *port) BackendRun(port); } #endif /* EXEC_BACKEND */ + PG_SETMASK(&UnBlockSig); if (pid < 0) { @@ -5013,12 +5051,13 @@ ExitPostmaster(int status) } /* - * sigusr1_handler - handle signal conditions from child processes + * Handle pmsignal conditions representing requests from backends, + * and check for promote and logrotate requests from pg_ctl. */ static void -sigusr1_handler(SIGNAL_ARGS) +process_action_request(Postmaster *postmaster) { - int save_errno = errno; + pending_action_request = false; /* * RECOVERY_STARTED and BEGIN_HOT_STANDBY signals are ignored in @@ -5143,7 +5182,7 @@ sigusr1_handler(SIGNAL_ARGS) */ if (CheckPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE)) { - PostmasterStateMachine(); + PostmasterStateMachine(postmaster); } if (StartupPID != 0 && @@ -5159,8 +5198,6 @@ sigusr1_handler(SIGNAL_ARGS) */ signal_child(StartupPID, SIGUSR2); } - - errno = save_errno; } /* @@ -5271,6 +5308,7 @@ StartChildProcess(AuxProcType type) { pid_t pid; + PG_SETMASK(&BlockSig); #ifdef EXEC_BACKEND { char *av[10]; @@ -5310,6 +5348,7 @@ StartChildProcess(AuxProcType type) AuxiliaryProcessMain(type); /* does not return */ } #endif /* EXEC_BACKEND */ + PG_SETMASK(&UnBlockSig); if (pid < 0) { diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c index eb3a569aae..3bfef592eb 100644 --- a/src/backend/storage/ipc/latch.c +++ b/src/backend/storage/ipc/latch.c @@ -283,6 +283,17 @@ InitializeLatchSupport(void) #ifdef WAIT_USE_SIGNALFD sigset_t signalfd_mask; + if (IsUnderPostmaster) + { + if (signal_fd != -1) + { + /* Release postmaster's signal FD; ignore any error */ + (void) close(signal_fd); + signal_fd = -1; + ReleaseExternalFD(); + } + } + /* Block SIGURG, because we'll receive it through a signalfd. */ sigaddset(&UnBlockSig, SIGURG); @@ -1069,6 +1080,7 @@ WaitEventAdjustEpoll(WaitEventSet *set, WaitEvent *event, int action) Assert(event->fd != PGINVALID_SOCKET); Assert(event->events & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE | + WL_SOCKET_IGNORE | WL_SOCKET_CLOSED)); if (event->events & WL_SOCKET_READABLE) @@ -1117,6 +1129,7 @@ WaitEventAdjustPoll(WaitEventSet *set, WaitEvent *event) { Assert(event->events & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE | + WL_SOCKET_IGNORE | WL_SOCKET_CLOSED)); pollfd->events = 0; if (event->events & WL_SOCKET_READABLE) @@ -1201,6 +1214,7 @@ WaitEventAdjustKqueue(WaitEventSet *set, WaitEvent *event, int old_events) event->events == WL_POSTMASTER_DEATH || (event->events & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE | + WL_SOCKET_IGNORE | WL_SOCKET_CLOSED))); if (event->events == WL_POSTMASTER_DEATH) @@ -1312,6 +1326,8 @@ WaitEventAdjustWin32(WaitEventSet *set, WaitEvent *event) flags |= FD_WRITE; if (event->events & WL_SOCKET_CONNECTED) flags |= FD_CONNECT; + if (event->events & WL_SOCKET_ACCEPT) + flags |= FD_ACCEPT; if (*handle == WSA_INVALID_EVENT) { @@ -2067,6 +2083,12 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout, /* connected */ occurred_events->events |= WL_SOCKET_CONNECTED; } + if ((cur_event->events & WL_SOCKET_ACCEPT) && + (resEvents.lNetworkEvents & FD_ACCEPT)) + { + /* incoming connection ready to accept */ + occurred_events->events |= WL_SOCKET_ACCEPT; + } if (resEvents.lNetworkEvents & FD_CLOSE) { /* EOF/error, so signal all caller-requested socket flags */ diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 3082093d1e..655e881688 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -24,7 +24,6 @@ #include <signal.h> #include <unistd.h> #include <sys/resource.h> -#include <sys/select.h> #include <sys/socket.h> #include <sys/time.h> diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index eb1046450b..1348261220 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -135,8 +135,7 @@ InitPostmasterChild(void) /* Initialize process-local latch support */ InitializeLatchSupport(); - MyLatch = &LocalLatchData; - InitLatch(MyLatch); + InitLocalLatch(); InitializeLatchWaitSet(); /* @@ -189,8 +188,7 @@ InitStandaloneProcess(const char *argv0) /* Initialize process-local latch support */ InitializeLatchSupport(); - MyLatch = &LocalLatchData; - InitLatch(MyLatch); + InitLocalLatch(); InitializeLatchWaitSet(); /* @@ -232,6 +230,13 @@ SwitchToSharedLatch(void) SetLatch(MyLatch); } +void +InitLocalLatch(void) +{ + MyLatch = &LocalLatchData; + InitLatch(MyLatch); +} + void SwitchBackToLocalLatch(void) { diff --git a/src/include/libpq/pqsignal.h b/src/include/libpq/pqsignal.h index 7890b426a8..76eb380a4f 100644 --- a/src/include/libpq/pqsignal.h +++ b/src/include/libpq/pqsignal.h @@ -53,7 +53,4 @@ extern PGDLLIMPORT sigset_t StartupBlockSig; extern void pqinitmask(void); -/* pqsigfunc is declared in src/include/port.h */ -extern pqsigfunc pqsignal_pm(int signo, pqsigfunc func); - #endif /* PQSIGNAL_H */ diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 795182fa51..0975867197 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -310,6 +310,7 @@ extern PGDLLIMPORT char *DatabasePath; /* now in utils/init/miscinit.c */ extern void InitPostmasterChild(void); extern void InitStandaloneProcess(const char *argv0); +extern void InitLocalLatch(void); extern void SwitchToSharedLatch(void); extern void SwitchBackToLocalLatch(void); diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index 68ab740f16..ce1f4bd44e 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -135,10 +135,17 @@ typedef struct Latch #define WL_SOCKET_CONNECTED WL_SOCKET_WRITEABLE #endif #define WL_SOCKET_CLOSED (1 << 7) +#ifdef WIN32 +#define WL_SOCKET_ACCEPT (1 << 8) +#else +#define WL_SOCKET_ACCEPT WL_SOCKET_READABLE +#endif +#define WL_SOCKET_IGNORE (1 << 9) #define WL_SOCKET_MASK (WL_SOCKET_READABLE | \ WL_SOCKET_WRITEABLE | \ WL_SOCKET_CONNECTED | \ - WL_SOCKET_CLOSED) + WL_SOCKET_CLOSED | \ + WL_SOCKET_ACCEPT) typedef struct WaitEvent { -- 2.38.1