Fix exit_handler in pgpool main process.
authorTatsuo Ishii <ishii@sraoss.co.jp>
Thu, 14 Apr 2022 11:01:56 +0000 (20:01 +0900)
committerTatsuo Ishii <ishii@sraoss.co.jp>
Thu, 14 Apr 2022 11:58:45 +0000 (20:58 +0900)
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
src/main/pgpool_main.c

index ff47184c347f2b6151cff8a528d2941b6054c861..a65726fc078fb7ef7a77511f2a4ecee4cb213a44 100644 (file)
@@ -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_TRANSATION 10 /* time in seconds to keep
index ebce553fd2a338f704cf702f32de3d101536390c..66d13e711ec516004481dbaefa1561506626aac4 100644 (file)
@@ -186,8 +186,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 */
@@ -1118,6 +1118,9 @@ terminate_all_childrens(int sig)
 }
 
 
+/*
+ * Pgpool main process exit handler
+ */
 static RETSIGTYPE exit_handler(int sig)
 {
        int                *walk;
@@ -1141,11 +1144,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)
        {