aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/storage/ipc/dsm_impl.c35
1 files changed, 22 insertions, 13 deletions
diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c
index 21e2a10669e..10c392c3f03 100644
--- a/src/backend/storage/ipc/dsm_impl.c
+++ b/src/backend/storage/ipc/dsm_impl.c
@@ -62,6 +62,7 @@
#endif
#include "common/file_perm.h"
+#include "libpq/pqsignal.h" /* for PG_SETMASK macro */
#include "miscadmin.h"
#include "pgstat.h"
#include "portability/mem.h"
@@ -306,14 +307,6 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
shm_unlink(name);
errno = save_errno;
- /*
- * If we received a query cancel or termination signal, we will have
- * EINTR set here. If the caller said that errors are OK here, check
- * for interrupts immediately.
- */
- if (errno == EINTR && elevel >= ERROR)
- CHECK_FOR_INTERRUPTS();
-
ereport(elevel,
(errcode_for_dynamic_shared_memory(),
errmsg("could not resize shared memory segment \"%s\" to %zu bytes: %m",
@@ -361,9 +354,21 @@ static int
dsm_impl_posix_resize(int fd, off_t size)
{
int rc;
+ int save_errno;
+
+ /*
+ * Block all blockable signals, except SIGQUIT. posix_fallocate() can run
+ * for quite a long time, and is an all-or-nothing operation. If we
+ * allowed SIGUSR1 to interrupt us repeatedly (for example, due to recovery
+ * conflicts), the retry loop might never succeed.
+ */
+ PG_SETMASK(&BlockSig);
/* Truncate (or extend) the file to the requested size. */
- rc = ftruncate(fd, size);
+ do
+ {
+ rc = ftruncate(fd, size);
+ } while (rc < 0 && errno == EINTR);
/*
* On Linux, a shm_open fd is backed by a tmpfs file. After resizing with
@@ -377,15 +382,15 @@ dsm_impl_posix_resize(int fd, off_t size)
if (rc == 0)
{
/*
- * We may get interrupted. If so, just retry unless there is an
- * interrupt pending. This avoids the possibility of looping forever
- * if another backend is repeatedly trying to interrupt us.
+ * We still use a traditional EINTR retry loop to handle SIGCONT.
+ * posix_fallocate() doesn't restart automatically, and we don't want
+ * this to fail if you attach a debugger.
*/
pgstat_report_wait_start(WAIT_EVENT_DSM_FILL_ZERO_WRITE);
do
{
rc = posix_fallocate(fd, 0, size);
- } while (rc == EINTR && !(ProcDiePending || QueryCancelPending));
+ } while (rc == EINTR);
pgstat_report_wait_end();
/*
@@ -397,6 +402,10 @@ dsm_impl_posix_resize(int fd, off_t size)
}
#endif /* HAVE_POSIX_FALLOCATE && __linux__ */
+ save_errno = errno;
+ PG_SETMASK(&UnBlockSig);
+ errno = save_errno;
+
return rc;
}