diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-06-02 21:03:25 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-06-02 21:03:25 +0000 |
commit | b5ebef7c4154d2423c68195a30cbcb37a2393054 (patch) | |
tree | 87679fb08d6e0588fc8b193cce0d22ef8b65d1c3 /src/backend/tcop/postgres.c | |
parent | 8dfb616606d411dd0ea7dc9980061cd9a94b1de7 (diff) | |
download | postgresql-b5ebef7c4154d2423c68195a30cbcb37a2393054.tar.gz postgresql-b5ebef7c4154d2423c68195a30cbcb37a2393054.zip |
Push enable/disable of notify and catchup interrupts all the way down
to just around the bare recv() call that gets a command from the client.
The former placement in PostgresMain was unsafe because the intermediate
processing layers (especially SSL) use facilities such as malloc that are
not necessarily re-entrant. Per report from counterstorm.com.
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r-- | src/backend/tcop/postgres.c | 82 |
1 files changed, 62 insertions, 20 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index fcb93d847d5..297eb75d890 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.445 2005/06/01 23:27:03 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.446 2005/06/02 21:03:24 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -112,6 +112,13 @@ static volatile sig_atomic_t got_SIGHUP = false; static bool xact_started = false; /* + * Flag to indicate that we are doing the outer loop's read-from-client, + * as opposed to any random read from client that might happen within + * commands like COPY FROM STDIN. + */ +static bool DoingCommandRead = false; + +/* * Flags to implement skip-till-Sync-after-error behavior for messages of * the extended query protocol. */ @@ -406,6 +413,52 @@ ReadCommand(StringInfo inBuf) return result; } +/* + * prepare_for_client_read -- set up to possibly block on client input + * + * This must be called immediately before any low-level read from the + * client connection. It is necessary to do it at a sufficiently low level + * that there won't be any other operations except the read kernel call + * itself between this call and the subsequent client_read_ended() call. + * In particular there mustn't be use of malloc() or other potentially + * non-reentrant libc functions. This restriction makes it safe for us + * to allow interrupt service routines to execute nontrivial code while + * we are waiting for input. + */ +void +prepare_for_client_read(void) +{ + if (DoingCommandRead) + { + /* Enable immediate processing of asynchronous signals */ + EnableNotifyInterrupt(); + EnableCatchupInterrupt(); + + /* Allow "die" interrupt to be processed while waiting */ + ImmediateInterruptOK = true; + + /* And don't forget to detect one that already arrived */ + QueryCancelPending = false; + CHECK_FOR_INTERRUPTS(); + } +} + +/* + * client_read_ended -- get out of the client-input state + */ +void +client_read_ended(void) +{ + if (DoingCommandRead) + { + ImmediateInterruptOK = false; + QueryCancelPending = false; /* forget any CANCEL signal */ + + DisableNotifyInterrupt(); + DisableCatchupInterrupt(); + } +} + /* * Parse a query string and pass it through the rewriter. @@ -2959,6 +3012,7 @@ PostgresMain(int argc, char *argv[], const char *username) * not in other exception-catching places since these interrupts * are only enabled while we wait for client input. */ + DoingCommandRead = false; DisableNotifyInterrupt(); DisableCatchupInterrupt(); @@ -3063,21 +3117,13 @@ PostgresMain(int argc, char *argv[], const char *username) } /* - * (2) deal with pending asynchronous NOTIFY from other backends, - * and enable async.c's signal handler to execute NOTIFY directly. - * Then set up other stuff needed before blocking for input. + * (2) Allow asynchronous signals to be executed immediately + * if they come in while we are waiting for client input. + * (This must be conditional since we don't want, say, reads on + * behalf of COPY FROM STDIN doing the same thing.) */ - QueryCancelPending = false; /* forget any earlier CANCEL - * signal */ - - EnableNotifyInterrupt(); - EnableCatchupInterrupt(); - - /* Allow "die" interrupt to be processed while waiting */ - ImmediateInterruptOK = true; - /* and don't forget to detect one that already arrived */ - QueryCancelPending = false; - CHECK_FOR_INTERRUPTS(); + QueryCancelPending = false; /* forget any earlier CANCEL signal */ + DoingCommandRead = true; /* * (3) read a command (loop blocks here) @@ -3087,11 +3133,7 @@ PostgresMain(int argc, char *argv[], const char *username) /* * (4) disable async signal conditions again. */ - ImmediateInterruptOK = false; - QueryCancelPending = false; /* forget any CANCEL signal */ - - DisableNotifyInterrupt(); - DisableCatchupInterrupt(); + DoingCommandRead = false; /* * (5) check for any other interesting events that happened while |