Re: fork() refactoring - Mailing list pgsql-patches

From Neil Conway
Subject Re: fork() refactoring
Date
Msg-id 422CEAAC.9030106@samurai.com
Whole thread Raw
In response to Re: fork() refactoring  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: fork() refactoring  (Neil Conway <neilc@samurai.com>)
List pgsql-patches
Tom Lane wrote:
> I'm worried about whether this doesn't break the EXEC_BACKEND case.
> Most of the code you've moved out isn't applicable to Windows, but
> the fflushes probably are

Right, which is why the patch adds fflushes to the Unix implementation
of internal_forkexec(). On reflection, it is probably more
straightforward to just invoke fork_process() from the Unix version of
internal_forkexec() -- attached is a revised patch that does this.

> Please do not apply without some further portability testing.

I've checked EXEC_BACKEND on Unix, and it seems to work. I don't have
access to a BeOS box, so I can't test that (and I wouldn't be surprised
if the port was pretty bitrotted already). Is there anything else you
want me to test before committing?

> I think it would be better to continue with your original thought of
> passing a token into this code so that the EXEC_BACKEND case could be
> handled too (the token would tell it which forkexec function to call).

The problem is that this was getting pretty complex; a lot of the
forkexec implementations want to pass data to the child process that is
private to the forkexec call site, for example. That means we still need
  an #ifdef EXEC_BACKEND -- i.e. it's not such a win over the simpler
fork_process(). Since Magnus said he's thinking of refactoring this
anyway, I'm happy to leave it to him.

-Neil
Index: src/backend/port/beos/support.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/port/beos/support.c,v
retrieving revision 1.11
diff -c -r1.11 support.c
*** src/backend/port/beos/support.c    25 Oct 2004 03:23:02 -0000    1.11
--- src/backend/port/beos/support.c    7 Mar 2005 23:36:03 -0000
***************
*** 265,271 ****



! /* The behavior of fork is borken on beos regarding shared memory. In fact
  all shared memory areas are clones in copy on write mode in the new process.

  We need to do a remapping of these areas. Just afer the fork we performe the
--- 265,271 ----



! /* The behavior of fork is broken on beos regarding shared memory. In fact
  all shared memory areas are clones in copy on write mode in the new process.

  We need to do a remapping of these areas. Just afer the fork we performe the
Index: src/backend/postmaster/Makefile
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/postmaster/Makefile,v
retrieving revision 1.19
diff -c -r1.19 Makefile
*** src/backend/postmaster/Makefile    5 Aug 2004 23:32:10 -0000    1.19
--- src/backend/postmaster/Makefile    7 Mar 2005 23:36:03 -0000
***************
*** 12,18 ****
  top_builddir = ../../..
  include $(top_builddir)/src/Makefile.global

! OBJS = postmaster.o bgwriter.o pgstat.o pgarch.o syslogger.o

  all: SUBSYS.o

--- 12,18 ----
  top_builddir = ../../..
  include $(top_builddir)/src/Makefile.global

! OBJS = bgwriter.o fork_process.o pgarch.o pgstat.o postmaster.o syslogger.o

  all: SUBSYS.o

Index: src/backend/postmaster/fork_process.c
===================================================================
RCS file: src/backend/postmaster/fork_process.c
diff -N src/backend/postmaster/fork_process.c
*** /dev/null    1 Jan 1970 00:00:00 -0000
--- src/backend/postmaster/fork_process.c    7 Mar 2005 23:36:03 -0000
***************
*** 0 ****
--- 1,80 ----
+ /*
+  * 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-2005, PostgreSQL Global Development Group
+  *
+  * IDENTIFICATION
+  *      $PostgreSQL$
+  */
+ #include "postgres.h"
+ #include "postmaster/fork_process.h"
+
+ #include <unistd.h>
+
+ /*
+  * 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.
+  */
+ pid_t
+ fork_process(void)
+ {
+     pid_t result;
+ #ifdef LINUX_PROFILE
+     struct itimerval prof_itimer;
+ #endif
+
+     /*
+      * Flush stdio channels just before fork, to avoid double-output
+      * problems. Ideally we'd use fflush(NULL) here, but there are still a
+      * few non-ANSI stdio libraries out there (like SunOS 4.1.x) that
+      * coredump if we do. Presently stdout and stderr are the only stdio
+      * output channels used by the postmaster, so fflush'ing them should
+      * be sufficient.
+      */
+     fflush(stdout);
+     fflush(stderr);
+
+ #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
+
+ #ifdef __BEOS__
+     /* Specific beos actions before backend startup */
+     beos_before_backend_startup();
+ #endif
+
+     result = fork();
+     if (result == (pid_t) -1)
+     {
+         /* fork failed */
+ #ifdef __BEOS__
+         /* Specific beos backend startup actions */
+         beos_backend_startup_failed();
+ #endif
+     }
+     else if (result == 0)
+     {
+         /* fork succeeded, in child */
+ #ifdef LINUX_PROFILE
+         setitimer(ITIMER_PROF, &prof_itimer, NULL);
+ #endif
+
+ #ifdef __BEOS__
+         /* Specific beos backend startup actions */
+         beos_backend_startup();
+ #endif
+     }
+
+     return result;
+ }
Index: src/backend/postmaster/pgarch.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/postmaster/pgarch.c,v
retrieving revision 1.14
diff -c -r1.14 pgarch.c
*** src/backend/postmaster/pgarch.c    31 Dec 2004 22:00:40 -0000    1.14
--- src/backend/postmaster/pgarch.c    7 Mar 2005 23:36:03 -0000
***************
*** 34,39 ****
--- 34,40 ----
  #include "access/xlog_internal.h"
  #include "libpq/pqsignal.h"
  #include "miscadmin.h"
+ #include "postmaster/fork_process.h"
  #include "postmaster/pgarch.h"
  #include "postmaster/postmaster.h"
  #include "storage/fd.h"
***************
*** 141,165 ****
          return 0;
      last_pgarch_start_time = curtime;

-     fflush(stdout);
-     fflush(stderr);
-
- #ifdef __BEOS__
-     /* Specific beos actions before backend startup */
-     beos_before_backend_startup();
- #endif
-
  #ifdef EXEC_BACKEND
      switch ((pgArchPid = pgarch_forkexec()))
  #else
!     switch ((pgArchPid = fork()))
  #endif
      {
          case -1:
- #ifdef __BEOS__
-             /* Specific beos actions */
-             beos_backend_startup_failed();
- #endif
              ereport(LOG,
                      (errmsg("could not fork archiver: %m")));
              return 0;
--- 142,154 ----
          return 0;
      last_pgarch_start_time = curtime;

  #ifdef EXEC_BACKEND
      switch ((pgArchPid = pgarch_forkexec()))
  #else
!     switch ((pgArchPid = fork_process()))
  #endif
      {
          case -1:
              ereport(LOG,
                      (errmsg("could not fork archiver: %m")));
              return 0;
***************
*** 167,176 ****
  #ifndef EXEC_BACKEND
          case 0:
              /* in postmaster child ... */
- #ifdef __BEOS__
-             /* Specific beos actions after backend startup */
-             beos_backend_startup();
- #endif
              /* Close the postmaster's sockets */
              ClosePostmasterPorts(false);

--- 156,161 ----
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.445
diff -c -r1.445 postmaster.c
*** src/backend/postmaster/postmaster.c    22 Feb 2005 04:36:36 -0000    1.445
--- src/backend/postmaster/postmaster.c    7 Mar 2005 23:37:07 -0000
***************
*** 92,97 ****
--- 92,99 ----
  #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
  #endif

+ #include "access/xlog.h"
+ #include "bootstrap/bootstrap.h"
  #include "catalog/pg_control.h"
  #include "catalog/pg_database.h"
  #include "commands/async.h"
***************
*** 103,125 ****
  #include "libpq/pqsignal.h"
  #include "miscadmin.h"
  #include "nodes/nodes.h"
! #include "postmaster/postmaster.h"
  #include "postmaster/pgarch.h"
  #include "postmaster/syslogger.h"
  #include "storage/fd.h"
  #include "storage/ipc.h"
  #include "storage/pg_shmem.h"
  #include "storage/pmsignal.h"
  #include "storage/proc.h"
- #include "storage/bufmgr.h"
- #include "access/xlog.h"
  #include "tcop/tcopprot.h"
  #include "utils/builtins.h"
  #include "utils/guc.h"
  #include "utils/memutils.h"
  #include "utils/ps_status.h"
- #include "bootstrap/bootstrap.h"
- #include "pgstat.h"

  #ifdef EXEC_BACKEND
  #include "storage/spin.h"
--- 105,126 ----
  #include "libpq/pqsignal.h"
  #include "miscadmin.h"
  #include "nodes/nodes.h"
! #include "pgstat.h"
! #include "postmaster/fork_process.h"
  #include "postmaster/pgarch.h"
+ #include "postmaster/postmaster.h"
  #include "postmaster/syslogger.h"
+ #include "storage/bufmgr.h"
  #include "storage/fd.h"
  #include "storage/ipc.h"
  #include "storage/pg_shmem.h"
  #include "storage/pmsignal.h"
  #include "storage/proc.h"
  #include "tcop/tcopprot.h"
  #include "utils/builtins.h"
  #include "utils/guc.h"
  #include "utils/memutils.h"
  #include "utils/ps_status.h"

  #ifdef EXEC_BACKEND
  #include "storage/spin.h"
***************
*** 1008,1023 ****
      int            i;
      pid_t        pid;

! #ifdef LINUX_PROFILE
!     struct itimerval prof_itimer;
! #endif
!
! #ifdef LINUX_PROFILE
!     /* see comments in BackendStartup */
!     getitimer(ITIMER_PROF, &prof_itimer);
! #endif
!
!     pid = fork();
      if (pid == (pid_t) -1)
      {
          write_stderr("%s: could not fork background process: %s\n",
--- 1009,1015 ----
      int            i;
      pid_t        pid;

!     pid = fork_process();
      if (pid == (pid_t) -1)
      {
          write_stderr("%s: could not fork background process: %s\n",
***************
*** 1030,1039 ****
          _exit(0);
      }

- #ifdef LINUX_PROFILE
-     setitimer(ITIMER_PROF, &prof_itimer, NULL);
- #endif
-
      MyProcPid = PostmasterPid = getpid();        /* reset PID vars to child */

  /* GH: If there's no setsid(), we hopefully don't need silent mode.
--- 1022,1027 ----
***************
*** 2382,2391 ****
      Backend    *bn;                /* for backend cleanup */
      pid_t        pid;

- #ifdef LINUX_PROFILE
-     struct itimerval prof_itimer;
- #endif
-
      /*
       * Compute the cancel key that will be assigned to this backend. The
       * backend will have its own copy in the forked-off process' value of
--- 2370,2375 ----
***************
*** 2409,2462 ****
      /* Pass down canAcceptConnections state (kluge for EXEC_BACKEND case) */
      port->canAcceptConnections = canAcceptConnections();

-     /*
-      * Flush stdio channels just before fork, to avoid double-output
-      * problems. Ideally we'd use fflush(NULL) here, but there are still a
-      * few non-ANSI stdio libraries out there (like SunOS 4.1.x) that
-      * coredump if we do. Presently stdout and stderr are the only stdio
-      * output channels used by the postmaster, so fflush'ing them should
-      * be sufficient.
-      */
-     fflush(stdout);
-     fflush(stderr);
-
  #ifdef EXEC_BACKEND
-
      pid = backend_forkexec(port);
-
  #else                            /* !EXEC_BACKEND */
!
! #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
!
! #ifdef __BEOS__
!     /* Specific beos actions before backend startup */
!     beos_before_backend_startup();
! #endif
!
!     pid = fork();
!
      if (pid == 0)                /* child */
      {
- #ifdef LINUX_PROFILE
-         setitimer(ITIMER_PROF, &prof_itimer, NULL);
- #endif
-
- #ifdef __BEOS__
-         /* Specific beos backend startup actions */
-         beos_backend_startup();
- #endif
          free(bn);
-
          proc_exit(BackendRun(port));
      }
  #endif   /* EXEC_BACKEND */
--- 2393,2405 ----
      /* Pass down canAcceptConnections state (kluge for EXEC_BACKEND case) */
      port->canAcceptConnections = canAcceptConnections();

  #ifdef EXEC_BACKEND
      pid = backend_forkexec(port);
  #else                            /* !EXEC_BACKEND */
!     pid = fork_process();
      if (pid == 0)                /* child */
      {
          free(bn);
          proc_exit(BackendRun(port));
      }
  #endif   /* EXEC_BACKEND */
***************
*** 2466,2475 ****
          /* in parent, fork failed */
          int            save_errno = errno;

- #ifdef __BEOS__
-         /* Specific beos backend startup actions */
-         beos_backend_startup_failed();
- #endif
          free(bn);
          errno = save_errno;
          ereport(LOG,
--- 2409,2414 ----
***************
*** 2945,2951 ****
      argv[2] = tmpfilename;

      /* Fire off execv in child */
!     if ((pid = fork()) == 0)
      {
          if (execv(postgres_exec_path, argv) < 0)
          {
--- 2884,2890 ----
      argv[2] = tmpfilename;

      /* Fire off execv in child */
!     if ((pid = fork_process()) == 0)
      {
          if (execv(postgres_exec_path, argv) < 0)
          {
***************
*** 3465,3474 ****
      int            ac = 0;
      char        xlbuf[32];

- #ifdef LINUX_PROFILE
-     struct itimerval prof_itimer;
- #endif
-
      /*
       * Set up command-line arguments for subprocess
       */
--- 3404,3409 ----
***************
*** 3488,3528 ****
      av[ac] = NULL;
      Assert(ac < lengthof(av));

-     /*
-      * Flush stdio channels (see comments in BackendStartup)
-      */
-     fflush(stdout);
-     fflush(stderr);
-
  #ifdef EXEC_BACKEND
-
      pid = postmaster_forkexec(ac, av);
-
  #else                            /* !EXEC_BACKEND */
!
! #ifdef LINUX_PROFILE
!     /* see comments in BackendStartup */
!     getitimer(ITIMER_PROF, &prof_itimer);
! #endif
!
! #ifdef __BEOS__
!     /* Specific beos actions before backend startup */
!     beos_before_backend_startup();
! #endif
!
!     pid = fork();

      if (pid == 0)                /* child */
      {
- #ifdef LINUX_PROFILE
-         setitimer(ITIMER_PROF, &prof_itimer, NULL);
- #endif
-
- #ifdef __BEOS__
-         /* Specific beos actions after backend startup */
-         beos_backend_startup();
- #endif
-
          IsUnderPostmaster = true;        /* we are a postmaster subprocess
                                           * now */

--- 3423,3435 ----
      av[ac] = NULL;
      Assert(ac < lengthof(av));

  #ifdef EXEC_BACKEND
      pid = postmaster_forkexec(ac, av);
  #else                            /* !EXEC_BACKEND */
!     pid = fork_process();

      if (pid == 0)                /* child */
      {
          IsUnderPostmaster = true;        /* we are a postmaster subprocess
                                           * now */

***************
*** 3546,3556 ****
      {
          /* in parent, fork failed */
          int            save_errno = errno;
-
- #ifdef __BEOS__
-         /* Specific beos actions before backend startup */
-         beos_backend_startup_failed();
- #endif
          errno = save_errno;
          switch (xlop)
          {
--- 3453,3458 ----
Index: src/backend/postmaster/syslogger.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/postmaster/syslogger.c,v
retrieving revision 1.12
diff -c -r1.12 syslogger.c
*** src/backend/postmaster/syslogger.c    1 Jan 2005 20:44:16 -0000    1.12
--- src/backend/postmaster/syslogger.c    7 Mar 2005 23:36:03 -0000
***************
*** 33,38 ****
--- 33,39 ----

  #include "libpq/pqsignal.h"
  #include "miscadmin.h"
+ #include "postmaster/fork_process.h"
  #include "postmaster/postmaster.h"
  #include "postmaster/syslogger.h"
  #include "pgtime.h"
***************
*** 451,478 ****

      pfree(filename);

-     /*
-      * Now we can fork off the syslogger subprocess.
-      */
-     fflush(stdout);
-     fflush(stderr);
-
- #ifdef __BEOS__
-     /* Specific beos actions before backend startup */
-     beos_before_backend_startup();
- #endif
-
  #ifdef EXEC_BACKEND
      switch ((sysloggerPid = syslogger_forkexec()))
  #else
!     switch ((sysloggerPid = fork()))
  #endif
      {
          case -1:
- #ifdef __BEOS__
-             /* Specific beos actions */
-             beos_backend_startup_failed();
- #endif
              ereport(LOG,
                      (errmsg("could not fork system logger: %m")));
              return 0;
--- 452,464 ----

      pfree(filename);

  #ifdef EXEC_BACKEND
      switch ((sysloggerPid = syslogger_forkexec()))
  #else
!     switch ((sysloggerPid = fork_process()))
  #endif
      {
          case -1:
              ereport(LOG,
                      (errmsg("could not fork system logger: %m")));
              return 0;
***************
*** 480,489 ****
  #ifndef EXEC_BACKEND
          case 0:
              /* in postmaster child ... */
- #ifdef __BEOS__
-             /* Specific beos actions after backend startup */
-             beos_backend_startup();
- #endif
              /* Close the postmaster's sockets */
              ClosePostmasterPorts(true);

--- 466,471 ----
Index: src/include/postmaster/fork_process.h
===================================================================
RCS file: src/include/postmaster/fork_process.h
diff -N src/include/postmaster/fork_process.h
*** /dev/null    1 Jan 1970 00:00:00 -0000
--- src/include/postmaster/fork_process.h    7 Mar 2005 23:36:03 -0000
***************
*** 0 ****
--- 1,8 ----
+ #ifndef FORK_PROCESS_H
+ #define FORK_PROCESS_H
+
+ #include "postgres.h"
+
+ extern pid_t fork_process(void);
+
+ #endif /* ! FORK_PROCESS_H */

pgsql-patches by date:

Previous
From: "Greg Sabino Mullane"
Date:
Subject: Re: Continue transactions after errors in psql
Next
From: Thomas F.O'Connell
Date:
Subject: pg_autovacuum UPDATE_INTERVAL cmd arg