summaryrefslogtreecommitdiffstats
path: root/src/backend/postmaster/fork_process.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 13:44:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 13:44:03 +0000
commit293913568e6a7a86fd1479e1cff8e2ecb58d6568 (patch)
treefc3b469a3ec5ab71b36ea97cc7aaddb838423a0c /src/backend/postmaster/fork_process.c
parentInitial commit. (diff)
downloadpostgresql-16-293913568e6a7a86fd1479e1cff8e2ecb58d6568.tar.xz
postgresql-16-293913568e6a7a86fd1479e1cff8e2ecb58d6568.zip
Adding upstream version 16.2.upstream/16.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/backend/postmaster/fork_process.c')
-rw-r--r--src/backend/postmaster/fork_process.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/src/backend/postmaster/fork_process.c b/src/backend/postmaster/fork_process.c
new file mode 100644
index 0000000..6f9c276
--- /dev/null
+++ b/src/backend/postmaster/fork_process.c
@@ -0,0 +1,126 @@
+/*
+ * fork_process.c
+ * A simple wrapper on top of fork(). This does not handle the
+ * EXEC_BACKEND case; it might be extended to do so, but it would be
+ * considerably more complex.
+ *
+ * Copyright (c) 1996-2023, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/postmaster/fork_process.c
+ */
+#include "postgres.h"
+
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "libpq/pqsignal.h"
+#include "postmaster/fork_process.h"
+
+#ifndef WIN32
+/*
+ * Wrapper for fork(). Return values are the same as those for fork():
+ * -1 if the fork failed, 0 in the child process, and the PID of the
+ * child in the parent process. Signals are blocked while forking, so
+ * the child must unblock.
+ */
+pid_t
+fork_process(void)
+{
+ pid_t result;
+ const char *oomfilename;
+ sigset_t save_mask;
+
+#ifdef LINUX_PROFILE
+ struct itimerval prof_itimer;
+#endif
+
+ /*
+ * Flush stdio channels just before fork, to avoid double-output problems.
+ */
+ fflush(NULL);
+
+#ifdef LINUX_PROFILE
+
+ /*
+ * Linux's fork() resets the profiling timer in the child process. If we
+ * want to profile child processes then we need to save and restore the
+ * timer setting. This is a waste of time if not profiling, however, so
+ * only do it if commanded by specific -DLINUX_PROFILE switch.
+ */
+ getitimer(ITIMER_PROF, &prof_itimer);
+#endif
+
+ /*
+ * We start postmaster children with signals blocked. This allows them to
+ * install their own handlers before unblocking, to avoid races where they
+ * might run the postmaster's handler and miss an important control
+ * signal. With more analysis this could potentially be relaxed.
+ */
+ sigprocmask(SIG_SETMASK, &BlockSig, &save_mask);
+ result = fork();
+ if (result == 0)
+ {
+ /* fork succeeded, in child */
+#ifdef LINUX_PROFILE
+ setitimer(ITIMER_PROF, &prof_itimer, NULL);
+#endif
+
+ /*
+ * By default, Linux tends to kill the postmaster in out-of-memory
+ * situations, because it blames the postmaster for the sum of child
+ * process sizes *including shared memory*. (This is unbelievably
+ * stupid, but the kernel hackers seem uninterested in improving it.)
+ * Therefore it's often a good idea to protect the postmaster by
+ * setting its OOM score adjustment negative (which has to be done in
+ * a root-owned startup script). Since the adjustment is inherited by
+ * child processes, this would ordinarily mean that all the
+ * postmaster's children are equally protected against OOM kill, which
+ * is not such a good idea. So we provide this code to allow the
+ * children to change their OOM score adjustments again. Both the
+ * file name to write to and the value to write are controlled by
+ * environment variables, which can be set by the same startup script
+ * that did the original adjustment.
+ */
+ oomfilename = getenv("PG_OOM_ADJUST_FILE");
+
+ if (oomfilename != NULL)
+ {
+ /*
+ * Use open() not stdio, to ensure we control the open flags. Some
+ * Linux security environments reject anything but O_WRONLY.
+ */
+ int fd = open(oomfilename, O_WRONLY, 0);
+
+ /* We ignore all errors */
+ if (fd >= 0)
+ {
+ const char *oomvalue = getenv("PG_OOM_ADJUST_VALUE");
+ int rc;
+
+ if (oomvalue == NULL) /* supply a useful default */
+ oomvalue = "0";
+
+ rc = write(fd, oomvalue, strlen(oomvalue));
+ (void) rc;
+ close(fd);
+ }
+ }
+
+ /* do post-fork initialization for random number generation */
+ pg_strong_random_init();
+ }
+ else
+ {
+ /* in parent, restore signal mask */
+ sigprocmask(SIG_SETMASK, &save_mask, NULL);
+ }
+
+ return result;
+}
+
+#endif /* ! WIN32 */