Ensure that 'errno' is saved and restored by all signal handlers that
authorTom Lane
Mon, 18 Dec 2000 17:33:42 +0000 (17:33 +0000)
committerTom Lane
Mon, 18 Dec 2000 17:33:42 +0000 (17:33 +0000)
might change it.  Experimentation shows that the signal handler call
mechanism does not save/restore errno for you, at least not on Linux
or HPUX, so this is definitely a real risk.

src/backend/commands/async.c
src/backend/postmaster/postmaster.c
src/backend/storage/lmgr/proc.c
src/backend/tcop/postgres.c
src/bin/psql/common.c
src/interfaces/libpq/fe-connect.c

index 6316262d042ff9e654763d07caf648a8bc2840fe..b86f2421eb8403fd9b0cb73d6c8f25f8536f6811 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.73 2000/11/28 23:27:54 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.74 2000/12/18 17:33:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -589,6 +589,7 @@ AtAbort_Notify()
 void
 Async_NotifyHandler(SIGNAL_ARGS)
 {
+   int         save_errno = errno;
 
    /*
     * Note: this is a SIGNAL HANDLER.  You must be very wary what you do
@@ -637,6 +638,8 @@ Async_NotifyHandler(SIGNAL_ARGS)
         */
        notifyInterruptOccurred = 1;
    }
+
+   errno = save_errno;
 }
 
 /*
index ca7f4fafa9c9277b91ee0255713b38dd40d4f5f6..c119f1301fe09c42848a2502dfe6e470efa67a38 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.198 2000/12/03 20:45:34 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.199 2000/12/18 17:33:40 tgl Exp $
  *
  * NOTES
  *
@@ -217,7 +217,7 @@ static int  initMasks(fd_set *rmask, fd_set *wmask);
 static char *canAcceptConnections(void);
 static long PostmasterRandom(void);
 static void RandomSalt(char *salt);
-static void SignalChildren(SIGNAL_ARGS);
+static void SignalChildren(int signal);
 static int CountChildren(void);
 static bool CreateOptsFile(int argc, char *argv[]);
 
@@ -1303,10 +1303,13 @@ reset_shared(unsigned short port)
 static void
 SIGHUP_handler(SIGNAL_ARGS)
 {
+   int         save_errno = errno;
+
    if (Shutdown > SmartShutdown)
        return;
    got_SIGHUP = true;
    SignalChildren(SIGHUP);
+   errno = save_errno;
 }
 
 
@@ -1317,6 +1320,8 @@ SIGHUP_handler(SIGNAL_ARGS)
 static void
 pmdie(SIGNAL_ARGS)
 {
+   int         save_errno = errno;
+
    PG_SETMASK(&BlockSig);
 
    if (DebugLvl >= 1)
@@ -1330,8 +1335,12 @@ pmdie(SIGNAL_ARGS)
             * Send SIGUSR2 to all children (AsyncNotifyHandler)
             */
            if (Shutdown > SmartShutdown)
+           {
+               errno = save_errno;
                return;
+           }
            SignalChildren(SIGUSR2);
+           errno = save_errno;
            return;
 
        case SIGTERM:
@@ -1342,24 +1351,34 @@ pmdie(SIGNAL_ARGS)
             * let children to end their work and ShutdownDataBase.
             */
            if (Shutdown >= SmartShutdown)
+           {
+               errno = save_errno;
                return;
+           }
            Shutdown = SmartShutdown;
            tnow = time(NULL);
            fprintf(stderr, "Smart Shutdown request at %s", ctime(&tnow));
            fflush(stderr);
            if (DLGetHead(BackendList)) /* let reaper() handle this */
+           {
+               errno = save_errno;
                return;
+           }
 
            /*
             * No children left. Shutdown data base system.
             */
            if (StartupPID > 0 || FatalError)   /* let reaper() handle
                                                 * this */
+           {
+               errno = save_errno;
                return;
+           }
            if (ShutdownPID > 0)
                abort();
 
            ShutdownPID = ShutdownDataBase();
+           errno = save_errno;
            return;
 
        case SIGINT:
@@ -1371,7 +1390,10 @@ pmdie(SIGNAL_ARGS)
             * and exit) and ShutdownDataBase.
             */
            if (Shutdown >= FastShutdown)
+           {
+               errno = save_errno;
                return;
+           }
            tnow = time(NULL);
            fprintf(stderr, "Fast Shutdown request at %s", ctime(&tnow));
            fflush(stderr);
@@ -1384,11 +1406,13 @@ pmdie(SIGNAL_ARGS)
                    fflush(stderr);
                    SignalChildren(SIGTERM);
                }
+               errno = save_errno;
                return;
            }
            if (Shutdown > NoShutdown)
            {
                Shutdown = FastShutdown;
+               errno = save_errno;
                return;
            }
            Shutdown = FastShutdown;
@@ -1398,11 +1422,15 @@ pmdie(SIGNAL_ARGS)
             */
            if (StartupPID > 0 || FatalError)   /* let reaper() handle
                                                 * this */
+           {
+               errno = save_errno;
                return;
+           }
            if (ShutdownPID > 0)
                abort();
 
            ShutdownPID = ShutdownDataBase();
+           errno = save_errno;
            return;
 
        case SIGQUIT:
@@ -1435,18 +1463,18 @@ pmdie(SIGNAL_ARGS)
 static void
 reaper(SIGNAL_ARGS)
 {
-/* GH: replace waitpid for !HAVE_WAITPID. Does this work ? */
+   int         save_errno = errno;
 #ifdef HAVE_WAITPID
    int         status;         /* backend exit status */
-
 #else
    union wait  status;         /* backend exit status */
-
 #endif
    int         exitstatus;
    int         pid;            /* process id of dead backend */
 
    PG_SETMASK(&BlockSig);
+   /* It's not really necessary to reset the handler each time is it? */
+   pqsignal(SIGCHLD, reaper);
 
    if (DebugLvl)
        fprintf(stderr, "%s: reaping dead processes...\n",
@@ -1499,12 +1527,11 @@ reaper(SIGNAL_ARGS)
            CheckPointPID = 0;
            checkpointed = time(NULL);
 
-           pqsignal(SIGCHLD, reaper);
+           errno = save_errno;
            return;
        }
        CleanupProc(pid, exitstatus);
    }
-   pqsignal(SIGCHLD, reaper);
 
    if (FatalError)
    {
@@ -1513,9 +1540,15 @@ reaper(SIGNAL_ARGS)
         * Wait for all children exit, then reset shmem and StartupDataBase.
         */
        if (DLGetHead(BackendList))
+       {
+           errno = save_errno;
            return;
+       }
        if (StartupPID > 0 || ShutdownPID > 0)
+       {
+           errno = save_errno;
            return;
+       }
        tnow = time(NULL);
        fprintf(stderr, "Server processes were terminated at %s"
                "Reinitializing shared memory and semaphores\n",
@@ -1526,18 +1559,26 @@ reaper(SIGNAL_ARGS)
        reset_shared(PostPortNumber);
 
        StartupPID = StartupDataBase();
+       errno = save_errno;
        return;
    }
 
    if (Shutdown > NoShutdown)
    {
        if (DLGetHead(BackendList))
+       {
+           errno = save_errno;
            return;
+       }
        if (StartupPID > 0 || ShutdownPID > 0)
+       {
+           errno = save_errno;
            return;
+       }
        ShutdownPID = ShutdownDataBase();
    }
 
+   errno = save_errno;
 }
 
 /*
@@ -2002,6 +2043,7 @@ ExitPostmaster(int status)
 static void
 dumpstatus(SIGNAL_ARGS)
 {
+   int         save_errno = errno;
    Dlelem     *curr;
 
    PG_SETMASK(&BlockSig);
@@ -2015,6 +2057,7 @@ dumpstatus(SIGNAL_ARGS)
        fprintf(stderr, "\tsock %d\n", port->sock);
        curr = DLGetSucc(curr);
    }
+   errno = save_errno;
 }
 
 /*
index a95432e0f8216c1f9ca5c2ffea65705bf0dbcb62..6b5159dbf04219c66e08633cc09051591da23b03 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.87 2000/12/18 00:44:47 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.88 2000/12/18 17:33:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  *     This is so that we can support more backends. (system-wide semaphore
  *     sets run out pretty fast.)                -ay 4/95
  *
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.87 2000/12/18 00:44:47 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.88 2000/12/18 17:33:41 tgl Exp $
  */
 #include "postgres.h"
 
+#include 
 #include 
 #include 
 #include 
@@ -298,7 +299,7 @@ InitProcess(void)
 }
 
 /* -----------------------
- * get off the wait queue
+ * get process off any wait queue it might be on
  * -----------------------
  */
 static bool
@@ -623,10 +624,11 @@ ins:;
    waitQueue->size++;
 
    lock->waitMask |= myMask;
-   SpinRelease(spinlock);
 
    MyProc->errType = NO_ERROR;     /* initialize result for success */
 
+   SpinRelease(spinlock);
+
    /* --------------
     * Set timer so we can wake up after awhile and check for a deadlock.
     * If a deadlock is detected, the handler releases the process's
@@ -826,6 +828,7 @@ ProcAddLock(SHM_QUEUE *elem)
 void
 HandleDeadLock(SIGNAL_ARGS)
 {
+   int         save_errno = errno;
    LOCK       *mywaitlock;
 
    LockLockTable();
@@ -846,6 +849,7 @@ HandleDeadLock(SIGNAL_ARGS)
        MyProc->links.next == INVALID_OFFSET)
    {
        UnlockLockTable();
+       errno = save_errno;
        return;
    }
 
@@ -858,6 +862,7 @@ HandleDeadLock(SIGNAL_ARGS)
    {
        /* No deadlock, so keep waiting */
        UnlockLockTable();
+       errno = save_errno;
        return;
    }
 
@@ -891,6 +896,7 @@ HandleDeadLock(SIGNAL_ARGS)
     * conditions.  i don't claim to understand this...
     */
    UnlockLockTable();
+   errno = save_errno;
 }
 
 void
index 706b5d1fbf136606dbcc5d3de7aff436eb26dd6e..02c1459052d7b5f209fd2cbf688d419b27537ad4 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.195 2000/12/18 00:44:47 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.196 2000/12/18 17:33:41 tgl Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
@@ -984,8 +984,11 @@ FloatExceptionHandler(SIGNAL_ARGS)
 static void
 QueryCancelHandler(SIGNAL_ARGS)
 {
+   int         save_errno = errno;
+
    QueryCancel = true;
    LockWaitCancel();
+   errno = save_errno;
 }
 
 void
@@ -1646,7 +1649,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
    if (!IsUnderPostmaster)
    {
        puts("\nPOSTGRES backend interactive interface ");
-       puts("$Revision: 1.195 $ $Date: 2000/12/18 00:44:47 $\n");
+       puts("$Revision: 1.196 $ $Date: 2000/12/18 17:33:41 $\n");
    }
 
    /*
index cc57771b70e3a083737358299dc2f7f530949b19..ccbbb6c144312e2b665392bc1393a7a21b137617 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.28 2000/12/15 17:54:43 petere Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.29 2000/12/18 17:33:42 tgl Exp $
  */
 #include "postgres.h"
 #include "common.h"
@@ -258,6 +258,8 @@ volatile bool cancel_pressed;
 void
 handle_sigint(SIGNAL_ARGS)
 {
+   int         save_errno = errno;
+
    /* Don't muck around if copying in or prompting for a password. */
    if ((copy_in_state && pset.cur_cmd_interactive) || prompt_state)
        return;
@@ -274,6 +276,7 @@ handle_sigint(SIGNAL_ARGS)
        write_stderr("Could not send cancel request: ");
        write_stderr(PQerrorMessage(cancelConn));
    }
+   errno = save_errno;         /* just in case the write changed it */
 }
 
 #endif  /* not WIN32 */
index c95ee99b94f147776342ff4540b29b6fa06a0ff6..868b73f6f7cb24640254e6287953de64af884368 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.154 2000/12/07 02:04:30 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.155 2000/12/18 17:33:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2084,6 +2084,7 @@ PQresetPoll(PGconn *conn)
  * malloc/free are often non-reentrant, and anything that might call them is
  * just as dangerous.  We avoid sprintf here for that reason.  Building up
  * error messages with strcpy/strcat is tedious but should be quite safe.
+ * We also save/restore errno in case the signal handler support doesn't.
  *
  * NOTE: this routine must not generate any error message longer than
  * INITIAL_EXPBUFFER_SIZE (currently 256), since we dare not try to
@@ -2093,6 +2094,7 @@ PQresetPoll(PGconn *conn)
 int
 PQrequestCancel(PGconn *conn)
 {
+   int         save_errno = errno;
    int         tmpsock = -1;
    struct
    {
@@ -2109,6 +2111,7 @@ PQrequestCancel(PGconn *conn)
        strcpy(conn->errorMessage.data,
               "PQrequestCancel() -- connection is not open\n");
        conn->errorMessage.len = strlen(conn->errorMessage.data);
+       errno = save_errno;
        return FALSE;
    }
 
@@ -2154,6 +2157,7 @@ PQrequestCancel(PGconn *conn)
    close(tmpsock);
 #endif
 
+   errno = save_errno;
    return TRUE;
 
 cancel_errReturn:
@@ -2168,6 +2172,7 @@ cancel_errReturn:
        close(tmpsock);
 #endif
    }
+   errno = save_errno;
    return FALSE;
 }