aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/ipc')
-rw-r--r--src/backend/storage/ipc/dsm_impl.c15
-rw-r--r--src/backend/storage/ipc/latch.c44
2 files changed, 55 insertions, 4 deletions
diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c
index 138bdec47e9..1972aecbedc 100644
--- a/src/backend/storage/ipc/dsm_impl.c
+++ b/src/backend/storage/ipc/dsm_impl.c
@@ -247,14 +247,17 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
/*
* Create new segment or open an existing one for attach.
*
- * Even though we're not going through fd.c, we should be safe against
- * running out of file descriptors, because of NUM_RESERVED_FDS. We're
- * only opening one extra descriptor here, and we'll close it before
- * returning.
+ * Even though we will close the FD before returning, it seems desirable
+ * to use Reserve/ReleaseExternalFD, to reduce the probability of EMFILE
+ * failure. The fact that we won't hold the FD open long justifies using
+ * ReserveExternalFD rather than AcquireExternalFD, though.
*/
+ ReserveExternalFD();
+
flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0);
if ((fd = shm_open(name, flags, PG_FILE_MODE_OWNER)) == -1)
{
+ ReleaseExternalFD();
if (errno != EEXIST)
ereport(elevel,
(errcode_for_dynamic_shared_memory(),
@@ -278,6 +281,7 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
/* Back out what's already been done. */
save_errno = errno;
close(fd);
+ ReleaseExternalFD();
errno = save_errno;
ereport(elevel,
@@ -295,6 +299,7 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
/* Back out what's already been done. */
save_errno = errno;
close(fd);
+ ReleaseExternalFD();
shm_unlink(name);
errno = save_errno;
@@ -323,6 +328,7 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
/* Back out what's already been done. */
save_errno = errno;
close(fd);
+ ReleaseExternalFD();
if (op == DSM_OP_CREATE)
shm_unlink(name);
errno = save_errno;
@@ -336,6 +342,7 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
*mapped_address = address;
*mapped_size = request_size;
close(fd);
+ ReleaseExternalFD();
return true;
}
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index cbd495225ca..046ca5c6c7e 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -51,6 +51,7 @@
#include "port/atomics.h"
#include "portability/instr_time.h"
#include "postmaster/postmaster.h"
+#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/latch.h"
#include "storage/pmsignal.h"
@@ -187,6 +188,9 @@ InitializeLatchSupport(void)
/* Clean up, just for safety's sake; we'll set these below */
selfpipe_readfd = selfpipe_writefd = -1;
selfpipe_owner_pid = 0;
+ /* Keep fd.c's accounting straight */
+ ReleaseExternalFD();
+ ReleaseExternalFD();
}
else
{
@@ -194,6 +198,7 @@ InitializeLatchSupport(void)
* Postmaster didn't create a self-pipe ... or else we're in an
* EXEC_BACKEND build, in which case it doesn't matter since the
* postmaster's pipe FDs were closed by the action of FD_CLOEXEC.
+ * fd.c won't have state to clean up, either.
*/
Assert(selfpipe_readfd == -1);
}
@@ -228,6 +233,10 @@ InitializeLatchSupport(void)
selfpipe_readfd = pipefd[0];
selfpipe_writefd = pipefd[1];
selfpipe_owner_pid = MyProcPid;
+
+ /* Tell fd.c about these two long-lived FDs */
+ ReserveExternalFD();
+ ReserveExternalFD();
#else
/* currently, nothing to do here for Windows */
#endif
@@ -604,24 +613,57 @@ CreateWaitEventSet(MemoryContext context, int nevents)
set->exit_on_postmaster_death = false;
#if defined(WAIT_USE_EPOLL)
+ if (!AcquireExternalFD())
+ {
+ /* treat this as though epoll_create1 itself returned EMFILE */
+ elog(ERROR, "epoll_create1 failed: %m");
+ }
#ifdef EPOLL_CLOEXEC
set->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (set->epoll_fd < 0)
+ {
+ ReleaseExternalFD();
elog(ERROR, "epoll_create1 failed: %m");
+ }
#else
/* cope with ancient glibc lacking epoll_create1 (e.g., RHEL5) */
set->epoll_fd = epoll_create(nevents);
if (set->epoll_fd < 0)
+ {
+ ReleaseExternalFD();
elog(ERROR, "epoll_create failed: %m");
+ }
if (fcntl(set->epoll_fd, F_SETFD, FD_CLOEXEC) == -1)
+ {
+ int save_errno = errno;
+
+ close(set->epoll_fd);
+ ReleaseExternalFD();
+ errno = save_errno;
elog(ERROR, "fcntl(F_SETFD) failed on epoll descriptor: %m");
+ }
#endif /* EPOLL_CLOEXEC */
#elif defined(WAIT_USE_KQUEUE)
+ if (!AcquireExternalFD())
+ {
+ /* treat this as though kqueue itself returned EMFILE */
+ elog(ERROR, "kqueue failed: %m");
+ }
set->kqueue_fd = kqueue();
if (set->kqueue_fd < 0)
+ {
+ ReleaseExternalFD();
elog(ERROR, "kqueue failed: %m");
+ }
if (fcntl(set->kqueue_fd, F_SETFD, FD_CLOEXEC) == -1)
+ {
+ int save_errno = errno;
+
+ close(set->kqueue_fd);
+ ReleaseExternalFD();
+ errno = save_errno;
elog(ERROR, "fcntl(F_SETFD) failed on kqueue descriptor: %m");
+ }
set->report_postmaster_not_running = false;
#elif defined(WAIT_USE_WIN32)
@@ -655,8 +697,10 @@ FreeWaitEventSet(WaitEventSet *set)
{
#if defined(WAIT_USE_EPOLL)
close(set->epoll_fd);
+ ReleaseExternalFD();
#elif defined(WAIT_USE_KQUEUE)
close(set->kqueue_fd);
+ ReleaseExternalFD();
#elif defined(WAIT_USE_WIN32)
WaitEvent *cur_event;