Skip to content

Commit 316c4c5

Browse files
committed
Clean up some problems in error recovery --- elog() was pretty broken
for the case of errors in backend startup, and proc_exit's method for coping with errors during proc_exit was *completely* busted. Fixed per discussions on pghackers around 11/6/99.
1 parent bb203c7 commit 316c4c5

File tree

3 files changed

+66
-70
lines changed

3 files changed

+66
-70
lines changed

src/backend/storage/ipc/ipc.c

Lines changed: 35 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*-------------------------------------------------------------------------
1+
/*-------------------------------------------------------------------------
22
*
33
* ipc.c
44
* POSTGRES inter-process communication definitions.
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.42 1999/11/06 19:46:57 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.43 1999/11/22 02:06:31 tgl Exp $
1111
*
1212
* NOTES
1313
*
@@ -28,8 +28,8 @@
2828
#include <sys/file.h>
2929
#include <errno.h>
3030

31-
3231
#include "postgres.h"
32+
3333
#include "storage/ipc.h"
3434
#include "storage/s_lock.h"
3535
/* In Ultrix, sem.h and shm.h must be included AFTER ipc.h */
@@ -43,6 +43,13 @@
4343
#include <sys/ipc.h>
4444
#endif
4545

46+
/*
47+
* This flag is set during proc_exit() to change elog()'s behavior,
48+
* so that an elog() from an on_proc_exit routine cannot get us out
49+
* of the exit procedure. We do NOT want to go back to the idle loop...
50+
*/
51+
bool proc_exit_inprogress = false;
52+
4653
static int UsePrivateMemory = 0;
4754

4855
static void IpcMemoryDetach(int status, char *shmaddr);
@@ -70,7 +77,8 @@ typedef struct _PrivateMemStruct
7077
char *memptr;
7178
} PrivateMem;
7279

73-
PrivateMem IpcPrivateMem[16];
80+
static PrivateMem IpcPrivateMem[16];
81+
7482

7583
static int
7684
PrivateMemoryCreate(IpcMemoryKey memKey,
@@ -105,45 +113,34 @@ PrivateMemoryAttach(IpcMemoryId memid)
105113
* -cim 2/6/90
106114
* ----------------------------------------------------------------
107115
*/
108-
static int proc_exit_inprogress = 0;
109-
110116
void
111117
proc_exit(int code)
112118
{
113-
int i;
114-
115-
TPRINTF(TRACE_VERBOSE, "proc_exit(%d) [#%d]", code, proc_exit_inprogress);
116-
117119
/*
118-
* If proc_exit is called too many times something bad is happening, so
119-
* exit immediately. This is crafted in two if's for a reason.
120+
* Once we set this flag, we are committed to exit. Any elog() will
121+
* NOT send control back to the main loop, but right back here.
120122
*/
123+
proc_exit_inprogress = true;
121124

122-
if (++proc_exit_inprogress == 9)
123-
elog(ERROR, "infinite recursion in proc_exit");
124-
if (proc_exit_inprogress >= 9)
125-
goto exit;
126-
127-
/* ----------------
128-
* if proc_exit_inprocess > 1, then it means that we
129-
* are being invoked from within an on_exit() handler
130-
* and so we return immediately to avoid recursion.
131-
* ----------------
132-
*/
133-
if (proc_exit_inprogress > 1)
134-
return;
125+
TPRINTF(TRACE_VERBOSE, "proc_exit(%d)", code);
135126

136127
/* do our shared memory exits first */
137128
shmem_exit(code);
138129

139130
/* ----------------
140131
* call all the callbacks registered before calling exit().
132+
*
133+
* Note that since we decrement on_proc_exit_index each time,
134+
* if a callback calls elog(ERROR) or elog(FATAL) then it won't
135+
* be invoked again when control comes back here (nor will the
136+
* previously-completed callbacks). So, an infinite loop
137+
* should not be possible.
141138
* ----------------
142139
*/
143-
for (i = on_proc_exit_index - 1; i >= 0; --i)
144-
(*on_proc_exit_list[i].function) (code, on_proc_exit_list[i].arg);
140+
while (--on_proc_exit_index >= 0)
141+
(*on_proc_exit_list[on_proc_exit_index].function) (code,
142+
on_proc_exit_list[on_proc_exit_index].arg);
145143

146-
exit:
147144
TPRINTF(TRACE_VERBOSE, "exit(%d)", code);
148145
exit(code);
149146
}
@@ -154,44 +151,23 @@ proc_exit(int code)
154151
* semaphores after a backend dies horribly
155152
* ------------------
156153
*/
157-
static int shmem_exit_inprogress = 0;
158-
159154
void
160155
shmem_exit(int code)
161156
{
162-
int i;
163-
164-
TPRINTF(TRACE_VERBOSE, "shmem_exit(%d) [#%d]",
165-
code, shmem_exit_inprogress);
166-
167-
/*
168-
* If shmem_exit is called too many times something bad is happenig,
169-
* so exit immediately.
170-
*/
171-
if (shmem_exit_inprogress > 9)
172-
{
173-
elog(ERROR, "infinite recursion in shmem_exit");
174-
exit(-1);
175-
}
176-
177-
/* ----------------
178-
* if shmem_exit_inprocess is true, then it means that we
179-
* are being invoked from within an on_exit() handler
180-
* and so we return immediately to avoid recursion.
181-
* ----------------
182-
*/
183-
if (shmem_exit_inprogress++)
184-
return;
157+
TPRINTF(TRACE_VERBOSE, "shmem_exit(%d)", code);
185158

186159
/* ----------------
187-
* call all the callbacks registered before calling exit().
160+
* call all the registered callbacks.
161+
*
162+
* As with proc_exit(), we remove each callback from the list
163+
* before calling it, to avoid infinite loop in case of error.
188164
* ----------------
189165
*/
190-
for (i = on_shmem_exit_index - 1; i >= 0; --i)
191-
(*on_shmem_exit_list[i].function) (code, on_shmem_exit_list[i].arg);
166+
while (--on_shmem_exit_index >= 0)
167+
(*on_shmem_exit_list[on_shmem_exit_index].function) (code,
168+
on_shmem_exit_list[on_shmem_exit_index].arg);
192169

193170
on_shmem_exit_index = 0;
194-
shmem_exit_inprogress = 0;
195171
}
196172

197173
/* ----------------------------------------------------------------
@@ -202,7 +178,7 @@ shmem_exit(int code)
202178
* ----------------------------------------------------------------
203179
*/
204180
int
205-
on_proc_exit(void (*function) (), caddr_t arg)
181+
on_proc_exit(void (*function) (), caddr_t arg)
206182
{
207183
if (on_proc_exit_index >= MAX_ON_EXITS)
208184
return -1;
@@ -223,7 +199,7 @@ int
223199
* ----------------------------------------------------------------
224200
*/
225201
int
226-
on_shmem_exit(void (*function) (), caddr_t arg)
202+
on_shmem_exit(void (*function) (), caddr_t arg)
227203
{
228204
if (on_shmem_exit_index >= MAX_ON_EXITS)
229205
return -1;

src/backend/utils/error/elog.c

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.51 1999/11/16 06:13:36 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.52 1999/11/22 02:06:31 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -30,6 +30,7 @@
3030
#include "libpq/libpq.h"
3131
#include "libpq/pqformat.h"
3232
#include "miscadmin.h"
33+
#include "storage/ipc.h"
3334
#include "storage/proc.h"
3435
#include "tcop/tcopprot.h"
3536
#include "utils/trace.h"
@@ -371,21 +372,38 @@ elog(int lev, const char *fmt, ...)
371372
*/
372373
if (lev == ERROR || lev == FATAL)
373374
{
374-
if (InError)
375+
/*
376+
* If we have not yet entered the main backend loop (ie, we are in
377+
* the postmaster or in backend startup), then go directly to
378+
* proc_exit. The same is true if anyone tries to report an error
379+
* after proc_exit has begun to run. (It's proc_exit's responsibility
380+
* to see that this doesn't turn into infinite recursion!) But in
381+
* the latter case, we exit with nonzero exit code to indicate that
382+
* something's pretty wrong.
383+
*/
384+
if (proc_exit_inprogress || ! Warn_restart_ready)
375385
{
376-
/* error reported during error recovery; don't loop forever */
377-
elog(REALLYFATAL, "elog: error during error recovery, giving up!");
386+
fflush(stdout);
387+
fflush(stderr);
388+
ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
389+
ProcReleaseLocks(); /* get rid of real locks we hold */
390+
/* XXX shouldn't proc_exit be doing the above?? */
391+
proc_exit((int) proc_exit_inprogress);
378392
}
393+
/*
394+
* Guard against infinite loop from elog() during error recovery.
395+
*/
396+
if (InError)
397+
elog(REALLYFATAL, "elog: error during error recovery, giving up!");
379398
InError = true;
399+
/*
400+
* Otherwise we can return to the main loop in postgres.c.
401+
* In the FATAL case, postgres.c will call proc_exit, but not
402+
* till after completing a standard transaction-abort sequence.
403+
*/
380404
ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
381-
if (! Warn_restart_ready)
382-
{
383-
/* error reported before there is a main loop to return to */
384-
elog(REALLYFATAL, "elog: error in postmaster or backend startup, giving up!");
385-
}
386405
if (lev == FATAL)
387406
ExitAfterAbort = true;
388-
/* exit to main loop */
389407
siglongjmp(Warn_restart, 1);
390408
}
391409

src/include/storage/ipc.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Id: ipc.h,v 1.36 1999/10/06 21:58:17 vadim Exp $
9+
* $Id: ipc.h,v 1.37 1999/11/22 02:06:30 tgl Exp $
1010
*
1111
* NOTES
1212
* This file is very architecture-specific. This stuff should actually
@@ -71,6 +71,8 @@ typedef int IpcMemoryId;
7171

7272

7373
/* ipc.c */
74+
extern bool proc_exit_inprogress;
75+
7476
extern void proc_exit(int code);
7577
extern void shmem_exit(int code);
7678
extern int on_shmem_exit(void (*function) (), caddr_t arg);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy