Thread: [Patch] Create a new session in postmaster by calling setsid()

[Patch] Create a new session in postmaster by calling setsid()

From
Paul Guo
Date:
Hello,

Recently I encountered an issue during testing and rootcaused it as the title mentioned.

postmaster children have done this (creating a new session) by calling InitPostmasterChild(),
but postmaster itself does not. This could lead to some issues (e..g signal handling). The test script below is a simple example.

$ cat test.sh
pg_ctl -D ./data -l stop.log stop
sleep 2 -- wait for pg down.
pg_ctl -D ./data -l start.log start
sleep 2 -- wait for pg up.
echo "pg_sleep()-ing"
psql -d postgres -c 'select pg_sleep(1000)'  -- press ctrl+c, then you will see postmaster and its children are all gone.

Long ago PG has pmdaemonize() to daemonize postmaster which of course create a new session. That code was removed in the patch below. 

commit f7ea6beaf4ca02b8e6dc576255e35a5b86035cb9
Author: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date:   Mon Jul 4 14:35:44 2011 +0300

    Remove silent_mode. You get the same functionality with "pg_ctl -l
    postmaster.log", or nohup.

    There was a small issue with LINUX_OOM_ADJ and silent_mode, namely that with
    silent_mode the postmaster process incorrectly used the OOM settings meant
    for backend processes. We certainly could've fixed that directly, but since
    silent_mode was redundant anyway, we might as well just remove it.

Here is the related discussion about the patch. It seems that is related to oom score setting in fork_process().

Personally I still like pg being a daemon, but probably I do not know some real cases which do not like daemon. If we do not go back to pgdaemonize() with further fix of fork_process() (assume I understand correctly) we could simply call setsid() in postmaster code to fix the issue above. I added a simple a patch as attached.

Thanks.


Attachment

Re: [Patch] Create a new session in postmaster by calling setsid()

From
Tom Lane
Date:
Paul Guo <pguo@pivotal.io> writes:
> [ make the postmaster execute setsid() too ]

I'm a bit skeptical of this proposal.  Forcing the postmaster to
dissociate from its controlling terminal is a good thing in some
scenarios, but probably less good in others, and manual postmaster
starts are probably mostly in the latter class.

I wonder whether having "pg_ctl start" do a setsid() would accomplish
the same result with less chance of breaking debugging usages.

            regards, tom lane


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Paul Guo
Date:


On Thu, Aug 2, 2018 at 10:30 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Paul Guo <pguo@pivotal.io> writes:
> [ make the postmaster execute setsid() too ]

I'm a bit skeptical of this proposal.  Forcing the postmaster to
dissociate from its controlling terminal is a good thing in some
scenarios, but probably less good in others, and manual postmaster
starts are probably mostly in the latter class.

I wonder whether having "pg_ctl start" do a setsid() would accomplish
the same result with less chance of breaking debugging usages.

                        regards, tom lane

Yes, if considering the case of starting postmaster manually, we can not create
a new session in postmaster, so pg_ctl seems to be a good place for setsid()
call. Attached a newer patch. Thanks.


Attachment

Re: [Patch] Create a new session in postmaster by calling setsid()

From
Michael Paquier
Date:
On Mon, Aug 06, 2018 at 12:11:26PM +0800, Paul Guo wrote:
> Yes, if considering the case of starting postmaster manually, we can not
> create
> a new session in postmaster, so pg_ctl seems to be a good place for setsid()
> call. Attached a newer patch. Thanks.

Hmm.  This patch breaks a feature of pg_ctl that I am really fond of for
development.  When starting a node which enters in recovery, I sometimes
use Ctrl-C to stop pg_ctl, which automatically makes the started
Postgres instance to stop, and this saves more strokes.  With your
patch, you don't get that anymore: when issuing Ctrl-C on pg_ctl then
the started instance still runs in the background.  I would be ready to
accept a patch which does not change the default behavior, and makes the
deamonization behavior activated only if an option switch is given by
the user, like -d/--daemon.  So I am -1 for what is proposed in its
current shape.
--
Michael

Attachment

Re: [Patch] Create a new session in postmaster by calling setsid()

From
Tom Lane
Date:
Michael Paquier <michael@paquier.xyz> writes:
> On Mon, Aug 06, 2018 at 12:11:26PM +0800, Paul Guo wrote:
>> Yes, if considering the case of starting postmaster manually, we can not
>> create
>> a new session in postmaster, so pg_ctl seems to be a good place for setsid()
>> call. Attached a newer patch. Thanks.

> Hmm.  This patch breaks a feature of pg_ctl that I am really fond of for
> development.  When starting a node which enters in recovery, I sometimes
> use Ctrl-C to stop pg_ctl, which automatically makes the started
> Postgres instance to stop, and this saves more strokes.  With your
> patch, you don't get that anymore: when issuing Ctrl-C on pg_ctl then
> the started instance still runs in the background.  I would be ready to
> accept a patch which does not change the default behavior, and makes the
> deamonization behavior activated only if an option switch is given by
> the user, like -d/--daemon.  So I am -1 for what is proposed in its
> current shape.

Hmm, that seems like a pretty niche usage.  I don't object to having
a switch to control this, but it seems to me that dissociating from
the terminal is by far the more commonly wanted behavior and so
ought to be the default.

            regards, tom lane


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Tom Lane
Date:
I wrote:
> Michael Paquier <michael@paquier.xyz> writes:
>> Hmm.  This patch breaks a feature of pg_ctl that I am really fond of for
>> development.  When starting a node which enters in recovery, I sometimes
>> use Ctrl-C to stop pg_ctl, which automatically makes the started
>> Postgres instance to stop, and this saves more strokes.  With your 
>> patch, you don't get that anymore: when issuing Ctrl-C on pg_ctl then
>> the started instance still runs in the background.  I would be ready to
>> accept a patch which does not change the default behavior, and makes the
>> deamonization behavior activated only if an option switch is given by
>> the user, like -d/--daemon.  So I am -1 for what is proposed in its
>> current shape.

> Hmm, that seems like a pretty niche usage.  I don't object to having
> a switch to control this, but it seems to me that dissociating from
> the terminal is by far the more commonly wanted behavior and so
> ought to be the default.

BTW, just thinking outside the box a bit --- perhaps the ideal behavior
to address Michael's use-case would be to have the postmaster itself
do setsid(), but not until it reaches the state of being ready to
accept client connections.

We'd likely need a switch to control that.  If memory serves, there
used to be such a switch, but we got rid of the postmaster's setsid
call and the switch too.  We probably should dig in the archives and
review the reasoning about that.

I'm still of the opinion that dissociating from the terminal ought to
be the default.  On at least some platforms, that happens automatically
because the postmaster's stdin, stdout, and stderr have been redirected
away from the terminal.  If we don't do it on platforms where setsid()
is necessary, then we have a cross-platform behavioral difference,
which generally doesn't seem like a good thing.

            regards, tom lane


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Andrew Gierth
Date:
>>>>> "Tom" == Tom Lane <tgl@sss.pgh.pa.us> writes:

 Tom> BTW, just thinking outside the box a bit --- perhaps the ideal
 Tom> behavior to address Michael's use-case would be to have the
 Tom> postmaster itself do setsid(), but not until it reaches the state
 Tom> of being ready to accept client connections.

 Tom> We'd likely need a switch to control that. If memory serves, there
 Tom> used to be such a switch, but we got rid of the postmaster's
 Tom> setsid call and the switch too. We probably should dig in the
 Tom> archives and review the reasoning about that.

The old silent_mode switch?

The tricky part about doing setsid() is this: you're not allowed to do
it if you're already a process group leader. silent_mode worked by
having postmaster do another fork, exit in the parent, and do setsid()
in the child.

If postmaster is launched from pg_ctl, then it won't be a group leader
unless pg_ctl made it one. But when it's run from the shell, it will be
if the shell does job control (the initial command of each shell job is
the group leader); if it's run from a service management process, then
it'll depend on what that process does.

-- 
Andrew (irc:RhodiumToad)


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Tom Lane
Date:
Andrew Gierth <andrew@tao11.riddles.org.uk> writes:
> "Tom" == Tom Lane <tgl@sss.pgh.pa.us> writes:
>  Tom> We'd likely need a switch to control that. If memory serves, there
>  Tom> used to be such a switch, but we got rid of the postmaster's
>  Tom> setsid call and the switch too. We probably should dig in the
>  Tom> archives and review the reasoning about that.

> The tricky part about doing setsid() is this: you're not allowed to do
> it if you're already a process group leader. silent_mode worked by
> having postmaster do another fork, exit in the parent, and do setsid()
> in the child.

Hmph.  Can't we just ignore that error?

            regards, tom lane


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Andrew Gierth
Date:
>>>>> "Tom" == Tom Lane <tgl@sss.pgh.pa.us> writes:

 >> The tricky part about doing setsid() is this: you're not allowed to
 >> do it if you're already a process group leader. silent_mode worked
 >> by having postmaster do another fork, exit in the parent, and do
 >> setsid() in the child.

 Tom> Hmph.  Can't we just ignore that error?

If you ignore the error from setsid(), then you're still a process group
leader (as you would be after running setsid()), but you're still
attached to whatever controlling terminal (if any) you were previously
attached to.

-- 
Andrew (irc:RhodiumToad)


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Tom Lane
Date:
Andrew Gierth <andrew@tao11.riddles.org.uk> writes:
> "Tom" == Tom Lane <tgl@sss.pgh.pa.us> writes:
>  Tom> Hmph.  Can't we just ignore that error?

> If you ignore the error from setsid(), then you're still a process group
> leader (as you would be after running setsid()), but you're still
> attached to whatever controlling terminal (if any) you were previously
> attached to.

Oh, got it.  So actually, the setsid has to be done by what is/will be
the postmaster process.

Although pg_ctl could sneak it in between forking and execing, it seems
like it'd be cleaner to have the postmaster proper do it in response to
a switch that pg_ctl passes it.  That avoids depending on the fork/exec
separation, and makes the functionality available for other postmaster
startup mechanisms, and opens the possibility of delaying the detach
to the end of startup.

            regards, tom lane


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Michael Paquier
Date:
On Wed, Sep 12, 2018 at 03:55:00PM -0400, Tom Lane wrote:
> Although pg_ctl could sneak it in between forking and execing, it seems
> like it'd be cleaner to have the postmaster proper do it in response to
> a switch that pg_ctl passes it.  That avoids depending on the fork/exec
> separation, and makes the functionality available for other postmaster
> startup mechanisms, and opens the possibility of delaying the detach
> to the end of startup.

I would be fine with something happening only once the postmaster thinks
that consistency has been reached and is open for business, though I'd
still think that this should be controlled by a switch, where the
default does what we do now.  Feel free to ignore me if I am outvoted ;)
--
Michael

Attachment

Re: [Patch] Create a new session in postmaster by calling setsid()

From
Paul Guo
Date:

On Thu, Sep 13, 2018 at 8:20 AM, Michael Paquier <michael@paquier.xyz> wrote:
On Wed, Sep 12, 2018 at 03:55:00PM -0400, Tom Lane wrote:
> Although pg_ctl could sneak it in between forking and execing, it seems
> like it'd be cleaner to have the postmaster proper do it in response to
> a switch that pg_ctl passes it.  That avoids depending on the fork/exec
> separation, and makes the functionality available for other postmaster
> startup mechanisms, and opens the possibility of delaying the detach
> to the end of startup.

I would be fine with something happening only once the postmaster thinks
that consistency has been reached and is open for business, though I'd
still think that this should be controlled by a switch, where the
default does what we do now.  Feel free to ignore me if I am outvoted ;)
--
Michael

From the respective of users instead of developers, I think for such important
service, tty should be dissociated, i.e. postmaster should be daemonized by
default (and even should have default log filename?) or be setsid()-ed at least.
For concerns from developers, maybe a shell alias, or an internal switch in pg_ctl,
or env variable guard in postmaster code could address.
 
I'm not sure the several-years-ago LINUX_OOM_ADJ issue (to resolve that,
silient_mode was removed) still exists or not. I don't have context  about that, so
I conceded to use setsid() even I prefer the deleted silent_mode code.

Re: [Patch] Create a new session in postmaster by calling setsid()

From
Andres Freund
Date:
Hi,

On 2018-09-13 15:27:58 +0800, Paul Guo wrote:
> From the respective of users instead of developers, I think for such
> important
> service, tty should be dissociated, i.e. postmaster should be daemonized by
> default (and even should have default log filename?) or be setsid()-ed at
> least.

I don't think it'd be good to switch to postgres daemonizing itself.  If
we were starting fresh, maybe, but there's plenty people invoking
postgres from scripts etc.  And tools like systemd don't actually want
daemons to fork away, so there's no clear need from that side either.


> I'm not sure the several-years-ago LINUX_OOM_ADJ issue (to resolve that,
> silient_mode was removed) still exists or not. I don't have context  about
> that, so
> I conceded to use setsid() even I prefer the deleted silent_mode code.

Yes, the OOM issues are still relevant.

Greetings,

Andres Freund


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Michael Paquier
Date:
On Thu, Sep 13, 2018 at 12:24:38PM -0700, Andres Freund wrote:
> On 2018-09-13 15:27:58 +0800, Paul Guo wrote:
>> From the respective of users instead of developers, I think for such
>> important
>> service, tty should be dissociated, i.e. postmaster should be daemonized by
>> default (and even should have default log filename?) or be setsid()-ed at
>> least.
>
> I don't think it'd be good to switch to postgres daemonizing itself.  If
> we were starting fresh, maybe, but there's plenty people invoking
> postgres from scripts etc.  And tools like systemd don't actually want
> daemons to fork away, so there's no clear need from that side either.

It seems to me that the thread is pointing out that we would not want
the postmaster to daemonize itself, but that something in pg_ctl could
be introduced, potentially optional.  I am marking this patch as
returned with feedback.
--
Michael

Attachment

Re: [Patch] Create a new session in postmaster by calling setsid()

From
Heikki Linnakangas
Date:
On 30/09/2018 15:47, Michael Paquier wrote:
> On Thu, Sep 13, 2018 at 12:24:38PM -0700, Andres Freund wrote:
>> On 2018-09-13 15:27:58 +0800, Paul Guo wrote:
>>>  From the respective of users instead of developers, I think for such
>>> important
>>> service, tty should be dissociated, i.e. postmaster should be daemonized by
>>> default (and even should have default log filename?) or be setsid()-ed at
>>> least.
>>
>> I don't think it'd be good to switch to postgres daemonizing itself.  If
>> we were starting fresh, maybe, but there's plenty people invoking
>> postgres from scripts etc.  And tools like systemd don't actually want
>> daemons to fork away, so there's no clear need from that side either.
> 
> It seems to me that the thread is pointing out that we would not want
> the postmaster to daemonize itself, but that something in pg_ctl could
> be introduced, potentially optional.  I am marking this patch as
> returned with feedback.

Hmm. So, the requirements are:

1. When launched from pg_ctl, postmaster should become leader of a new 
session and process group. To address Paul's original scenario.

2. If "postmaster" is launched stand-alone from terminal or a script, it 
should stay in foreground, in the parent session, so that it can be 
killed with Ctrl-C.

3. Hitting Ctrl-C while "pg_ctl start -w" is waiting for postmaster to 
start up, should "abort" and kill postmaster.

We talked about adding a flag to postmaster, to tell it to call 
setsid(). But I'm not sure what would be the appropriate time to do it. 
If it's done early during postmaster startup, then we still wouldn't 
have solved 3. Hitting Ctrl-C on pg_ctl, while the server is still in 
recovery, would not kill the server. We could do it after recovery has 
finished, but if we have already launched auxiliar processes, I think 
they would stay in the old process group and session. So I don't think 
that works.

Another idea would be to call setsid() in pg_ctl, after forking 
postmaster, like in Paul's original patch. That solves 1. and 2. To 
still do 3., add a signal handler for SIGINT in pg_ctl, which forwards 
the SIGINT to the postmaster process. Thoughts on that?

- Heikki


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Tom Lane
Date:
Heikki Linnakangas <hlinnaka@iki.fi> writes:
> We talked about adding a flag to postmaster, to tell it to call 
> setsid(). But I'm not sure what would be the appropriate time to do it. 

Yeah, there's no ideal time in the postmaster.

> Another idea would be to call setsid() in pg_ctl, after forking 
> postmaster, like in Paul's original patch. That solves 1. and 2. To 
> still do 3., add a signal handler for SIGINT in pg_ctl, which forwards 
> the SIGINT to the postmaster process. Thoughts on that?

That seems like a nice idea.

            regards, tom lane


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Heikki Linnakangas
Date:
On 28/12/2018 22:13, Tom Lane wrote:
> Heikki Linnakangas <hlinnaka@iki.fi> writes:
>> Another idea would be to call setsid() in pg_ctl, after forking
>> postmaster, like in Paul's original patch. That solves 1. and 2. To
>> still do 3., add a signal handler for SIGINT in pg_ctl, which forwards
>> the SIGINT to the postmaster process. Thoughts on that?
> 
> That seems like a nice idea.

Here's a patch to implement that. Seems to work. There is a small window 
between launching postmaster and installing the signal handler, though, 
where CTRL-C on pg_ctl will not abort the server launch. I think that's 
acceptable.

Looking at the existing docs in the "Starting the Database Server" 
section, and the pg_ctl reference page, I don't think we need to change 
anything. This is the same user-visible behavior as before, except for 
the case with a script like in Paul's original post. And that is almost 
a bug fix: the manual says that pg_ctl "will start the server in the 
background", and I think the new behavior matches that description 
better than the old one. Perhaps we should mention something about how 
CTRL-C will interrupt the server launch in "pg_ctl -w" mode, but that 
isn't new, either.

I don't think we should backpatch this. We haven't heard any complaints 
about this until now, and it seems plausible, although unlikely, that 
someone might be relying on the current behavior.

- Heikki


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Heikki Linnakangas
Date:
On 30/12/2018 21:59, Heikki Linnakangas wrote:
> On 28/12/2018 22:13, Tom Lane wrote:
>> Heikki Linnakangas <hlinnaka@iki.fi> writes:
>>> Another idea would be to call setsid() in pg_ctl, after forking
>>> postmaster, like in Paul's original patch. That solves 1. and 2. To
>>> still do 3., add a signal handler for SIGINT in pg_ctl, which forwards
>>> the SIGINT to the postmaster process. Thoughts on that?
>>
>> That seems like a nice idea.
> 
> Here's a patch to implement that.

Forgot attachment, here it is.

- Heikki

Attachment

Re: [Patch] Create a new session in postmaster by calling setsid()

From
Tom Lane
Date:
Heikki Linnakangas <hlinnaka@iki.fi> writes:
> Here's a patch to implement that. Seems to work. There is a small window 
> between launching postmaster and installing the signal handler, though, 
> where CTRL-C on pg_ctl will not abort the server launch. I think that's 
> acceptable.

Hm ... you could partially forestall that by installing the signal handler
first.  But then you have to assume that storing a pid_t variable is
atomic, which perhaps is bad?  Though it's hard to credit that any
platform would need multiple instructions to do that.  Also, I suppose
there's still a window, since the fork will necessarily occur some time
before you're able to store the child PID into the variable.

Another possible idea is to block SIGINT from before the fork till after
you've set the variable.  But that seems overly complicated, and perhaps
not without problems of its own.  So on the whole I concur with your
approach.

> Forgot attachment, here it is.

This comment needs copy-editing:

+         * If the user hits interrupts the startup (e.g. with CTRL-C), we'd

Looks good otherwise.

            regards, tom lane


Re: [Patch] Create a new session in postmaster by calling setsid()

From
Heikki Linnakangas
Date:
On 30/12/2018 22:56, Tom Lane wrote:
> This comment needs copy-editing:
> 
> +         * If the user hits interrupts the startup (e.g. with CTRL-C), we'd
> 
> Looks good otherwise.

Thanks, fixed that, and pushed.

- Heikki