9 messages in com.xensource.lists.xen-develRe: [Xen-devel] Re: [PATCH] setsid() ...
FromSent OnAttachments
Horms26 Nov 2005 03:43 
Horms27 Nov 2005 20:28 
Ewan Mellor28 Nov 2005 03:31 
Horms28 Nov 2005 04:52 
Ewan Mellor28 Nov 2005 05:36 
Horms28 Nov 2005 05:57 
Ewan Mellor28 Nov 2005 07:56 
Horms28 Nov 2005 17:51 
Horms29 Nov 2005 18:33 
Subject:Re: [Xen-devel] Re: [PATCH] setsid() exception in xend
From:Ewan Mellor (ew@xensource.com)
Date:11/28/2005 05:36:51 AM
List:com.xensource.lists.xen-devel

On Mon, Nov 28, 2005 at 12:53:17PM +0000, Horms wrote:

Ewan Mellor <ew@xensource.com> wrote:

On Mon, Nov 28, 2005 at 04:29:04AM +0000, Horms wrote:

[Re: forking / setsid'ing patch]

Hi Horms,

How are you running Xend? There's a call to fork in fork_pid, and no-one's had a problem with this or setsid before.

Hi Ewan,

at the time that I noticed the problem, my machine was doing some very strange things that I won't go into. I can't actually reproduce the exception now that I fixed the box up.

However, I do think that there is a minor problem. My previous patch seemed to solve it, but I think it was slightly wrong, as you point out by the time daemonize() is called, the code is already running as a child.

The thing that I think is missing is that after calling setsid(), fork() needs to be called again. This allows the session leader (the process that called setsid()) to exit, and this its children have no way of regaining the terminal.

Here is a slightly revised patch that puts a second fork() after setsid() (rather than before as the previous incarnation did). If you look at the output of ps you should with and without this patch, and see that the assosiation with the terminal disapears.

I agree that the second fork is required, so you're on the right track, but the rest of the patch seems problematic to me. Do we really need to have the grandchild write to the child, just so that the child can write to the parent (hunk 1 of your patch)? Why not just pass the descriptor from grandparent to grandchild directly? I think that this would mean that the daemonize process could keep it's original interface, and just perform the extra fork, with no other changes.

Even if the intermediate pipe is required, closing one descriptor called "status" and then opening a new one and assigning that to status just for it to be returned from the function is unreasonably complicated.

Ewan.

As for why the previous patch worked, I'm not entirely sure.

# HG changeset patch # User Horms <hor@verge.net.au> # Node ID 86339c0ea955b837c3185d500d4ebbb3a5f448c3 # Parent ddd958718cde22f20371a58359e173fd21c5da2e [xend] Detach from terminal

* For setsid to effectivley detach a process from the terminal, the following needs to occur:

fork () Return control to the shell setsid () New session with no controlling terminal fork () The session leader (parent) exits and thus the resulting child process can never regain the terminal

This patch adds the second fork

* The call to self.daemonize(), which now forks, is moved to run before self.tracing(), as not that it actually disconnects from the terminal, and thus the prevailing process, the trace looses the processes created in self.run().

diff -r ddd958718cde -r 86339c0ea955 tools/python/xen/xend/server/SrvDaemon.py --- a/tools/python/xen/xend/server/SrvDaemon.py Mon Nov 28 12:35:11 2005 +++ b/tools/python/xen/xend/server/SrvDaemon.py Mon Nov 28 12:45:57 2005 @@ -121,10 +121,34 @@

return self.child

- def daemonize(self): + def daemonize(self, status): if not XEND_DAEMONIZE: return + # Detach from TTY. + + # Become the group leader (already a child process) os.setsid() + + # Fork, this allows the group leader to exit, + # which means the child can never again regain control of the + # terminal + r, w = os.pipe() + if self.fork_pid(XEND_PID_FILE): + os.close(w) + r = os.fdopen(r, 'r') + try: + s = r.read() + finally: + r.close() + if len(s): + status.write(s) + status.close() + self.exit() + + # Child + os.close(r); + status.close(); + status = os.fdopen(w, 'w')

# Detach from standard file descriptors, and redirect them to # /dev/null or the log as appropriate. @@ -140,6 +164,8 @@ os.dup(0) os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)

+ return status +

def start(self, trace=0): """Attempts to start the daemons. @@ -164,7 +190,7 @@ # we can avoid a race condition during startup

r,w = os.pipe() - if self.fork_pid(XEND_PID_FILE): + if os.fork(): os.close(w) r = os.fdopen(r, 'r') try: @@ -178,8 +204,9 @@ else: os.close(r) # Child + status = self.daemonize(os.fdopen(w, 'w')) self.tracing(trace) - self.run(os.fdopen(w, 'w')) + self.run(status)

return ret

@@ -274,7 +301,6 @@

relocate.listenRelocation() servers = SrvServer.create() - self.daemonize() servers.start(status) except Exception, ex: print >>sys.stderr, 'Exception starting xend:', ex