pgpool2.git / summary / log / commit / refs

commit    f2d5a3b815cece78eeef0163d262656b4562d443
Author:   Tatsuo Ishii <ishii@sraoss.co.jp>
Date:     Thu Apr 14 11:01:56 2022 +0000

    Fix exit_handler in pgpool main process.
    
    It was allowed to be interrupted by signals (SIGTERM, SIGINT and
    SOGQUIT) while the exit_handler. As a resit, exit_handler is executed
    while executing exit_handler. This could cause infinite wait in
    terminate_childrens() which is called from exit_handler.  To prevent
    this, protect variable "exiting" using semaphore to make sure that
    only one instance of exit_handler runs at the same time.
    
    Discussion: https://www.pgpool.net/pipermail/pgpool-hackers/2022-April/004149.html


src/include/pool.h | 3 ++- src/main/pgpool_main.c | 44 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/include/pool.h b/src/include/pool.h index 1a892fc61..c8d97abfd 100644 --- a/src/include/pool.h +++ b/src/include/pool.h @@ -379,7 +379,7 @@ typedef enum #define Min(x, y) ((x) < (y) ? (x) : (y)) -#define MAX_NUM_SEMAPHORES 8 +#define MAX_NUM_SEMAPHORES 9 #define CONN_COUNTER_SEM 0 #define REQUEST_INFO_SEM 1 #define SHM_CACHE_SEM 2 @@ -388,6 +388,7 @@ typedef enum #define ACCEPT_FD_SEM 5 #define SI_CRITICAL_REGION_SEM 6 #define FOLLOW_PRIMARY_SEM 7 +#define MAIN_EXIT_HANDLER_SEM 8 /* used in exit_hander in pgpool main process */ #define MAX_REQUEST_QUEUE_SIZE 10 #define MAX_SEC_WAIT_FOR_CLUSTER_TRANSACTION 10 /* time in seconds to keep diff --git a/src/main/pgpool_main.c b/src/main/pgpool_main.c index 861d9a27d..f0d362ac1 100644 --- a/src/main/pgpool_main.c +++ b/src/main/pgpool_main.c @@ -229,8 +229,8 @@ extern char *pcp_conf_file; /* path for pcp.conf */ extern char *conf_file; extern char *hba_file; -static int exiting = 0; /* non 0 if I'm exiting */ -static int switching = 0; /* non 0 if I'm failing over or degenerating */ +static volatile sig_atomic_t exiting = 0; /* non 0 if I'm exiting */ +static volatile sig_atomic_t switching = 0; /* non 0 if I'm failing over or degenerating */ POOL_REQUEST_INFO *Req_info; /* request info area in shared memory */ volatile sig_atomic_t *InRecovery; /* non 0 if recovery is started */ @@ -1098,6 +1098,9 @@ terminate_all_childrens(int sig) } +/* + * Pgpool main process exit handler + */ static RETSIGTYPE exit_handler(int sig) { int *walk; @@ -1121,11 +1124,42 @@ static RETSIGTYPE exit_handler(int sig) errno = save_errno; return; } - exiting = 1; - processState = EXITING; + /* + * Check if another exit handler instance is already running. It is + * possible that exit_handler is interrupted in the middle by other + * signal. + */ + if (exiting) + { + ereport(LOG, + (errmsg("exit handler (signal: %d) called. but exit handler is already in progress", sig))); + POOL_SETMASK(&UnBlockSig); + errno = save_errno; + return; + } + + /* Check to make sure that other exit handler is not running */ + pool_semaphore_lock(MAIN_EXIT_HANDLER_SEM); + if (exiting == 0) + { + exiting = 1; + pool_semaphore_unlock(MAIN_EXIT_HANDLER_SEM); + } + else + { + pool_semaphore_unlock(MAIN_EXIT_HANDLER_SEM); + ereport(LOG, + (errmsg("exit handler (signal: %d) called. but exit handler is already in progress", sig))); + POOL_SETMASK(&UnBlockSig); + errno = save_errno; + return; + } + + processState = EXITING; ereport(LOG, - (errmsg("shutting down"))); + (errmsg("shutting down by signal %d", sig))); + /* Close listen socket if they are already initialized */ if (fds) { [parent: c13231cd2a08]