diff options
Diffstat (limited to 'src/backend/storage/ipc')
-rw-r--r-- | src/backend/storage/ipc/dsm_impl.c | 15 | ||||
-rw-r--r-- | src/backend/storage/ipc/latch.c | 44 |
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; |