Skip to contentSkip to conversation

properly daemonize vncviewer

PATCH In review Charles Coffing 2 participants 3 messages Aug 1, 2006 – Aug 2, 2006

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 properly daemonize vncviewer

Hi,

Currently, vncviewer is spawned from xm, but it doesn't properly get daemonized. The attached patch makes vncviewer run completely separate from xm.

There are various reasons it should be daemonized, but the particular problem we hit was that YaST called "xm create" and waited on output on stdout/stderr; xm then spawned vncviewer (which never closed its inherited stdout and stderr); xm then would exit, but YaST still had open file descriptors, and therefore waited forever. It would be possible to work around in YaST, but it seemed cleaner to daemonize vncviewer.

We've been running with a variant of this patch (a variant because we use tightvnc, which requires different arguments) for many months, and it works well.

Please consider applying to xen-unstable.

Thanks.

tools/python/xen/xm/create.py +40 -2
Index: xen-unstable/tools/python/xen/xm/create.py
===================================================================
@@ -857,11 +857,49 @@ def choose_vnc_display():
 vncpid = None
 
 def spawn_vnc(display):
+    """Spawns a vncviewer that listens on the specified display.  On success,
+    returns the port that the vncviewer is listening on and sets the global
+    vncpid.  On failure, returns 0.  Note that vncviewer is daemonized.
+    """
     vncargs = (["vncviewer", "-log", "*:stdout:0",
             "-listen", "%d" % (VNC_BASE_PORT + display) ])
-    global vncpid    
-    vncpid = os.spawnvp(os.P_NOWAIT, "vncviewer", vncargs)
 
+    r, w = os.pipe()
+    pid = os.fork()
+
+    if pid == 0:
+        os.close(r)
+        w = os.fdopen(w, 'w')
+        os.setsid()
+        try:
+            pid2 = os.fork()
+        except:
+            pid2 = None
+        if pid2 == 0:
+            os.chdir("/")
+            for fd in range(0, 256):
+                try:
+                    os.close(fd)
+                except:
+                    pass
+            os.open("/dev/null", os.O_RDWR)
+            os.dup2(0, 1)
+            os.dup2(0, 2)
+            os.execvp("vncviewer", vncargs)
+            os._exit(1)
+        else:
+            w.write(str(pid2 or 0))
+            w.close()
+            os._exit(0)
+
+    global vncpid
+    os.close(w)
+    r = os.fdopen(r)
+    vncpid = int(r.read())
+    r.close()
+    os.waitpid(pid, 0)
+    if vncpid == 0:
+        return 0
     return VNC_BASE_PORT + display
     
 def preprocess_vnc(vals):

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

#1 lore raw
Quoted 5 lines · Charles Coffing

We've been running with a variant of this patch (a variant because we use tightvnc, which requires different arguments) for many months, and it works well.

Please consider applying to xen-unstable.

Is there no Python library function that can do this (I couldn't find one)?

If not, can you at least put the new code in a function with a spawn-like interface (i.e., takes two parameters -- program name and program argument list). It's okay to put the new function somewhere nearby in create.py.

-- Keir

#2 lore raw
Quoted 3 lines · Keir Fraser
Quoted 1 line · Charles Coffing

We've been running with a variant of this patch (a variant because

we

Quoted 1 line
Quoted 1 line

use tightvnc, which requires different arguments) for many months,

and

Quoted 7 lines
Quoted 3 lines

it works well.

Please consider applying to xen- unstable.

Is there no Python library function that can do this (I couldn't find

one)?

No. And as an added twist, I wanted to get the PID of the daemonized program back (without the mess or risk of writing to a temporary file) and I didn't see any such thing out there already.

Quoted 2 lines

If not, can you at least put the new code in a function with a spawn- like interface (i.e., takes two parameters -- program name

and

Quoted 2 lines

program argument list). It's okay to put the new function somewhere nearby in create.py.

I've attached the updated patch with the suggested changes.

tools/python/xen/xm/create.py +48 -4
Index: xen-3.0-testing/tools/python/xen/xm/create.py
===================================================================
@@ -765,14 +765,58 @@ def choose_vnc_display():
 
 vncpid = None
 
+def daemonize(prog, args):
+    """Runs a program as a daemon with the list of arguments.  Returns the PID
+    of the daemonized program, or returns 0 on error.
+    """
+    r, w = os.pipe()
+    pid = os.fork()
+
+    if pid == 0:
+        os.close(r)
+        w = os.fdopen(w, 'w')
+        os.setsid()
+        try:
+            pid2 = os.fork()
+        except:
+            pid2 = None
+        if pid2 == 0:
+            os.chdir("/")
+            for fd in range(0, 256):
+                try:
+                    os.close(fd)
+                except:
+                    pass
+            os.open("/dev/null", os.O_RDWR)
+            os.dup2(0, 1)
+            os.dup2(0, 2)
+            os.execvp(prog, args)
+            os._exit(1)
+        else:
+            w.write(str(pid2 or 0))
+            w.close()
+            os._exit(0)
+
+    os.close(w)
+    r = os.fdopen(r)
+    daemon_pid = int(r.read())
+    r.close()
+    os.waitpid(pid, 0)
+    return daemon_pid
+
 def spawn_vnc(display):
+    """Spawns a vncviewer that listens on the specified display.  On success,
+    returns the port that the vncviewer is listening on and sets the global
+    vncpid.  On failure, returns 0.  Note that vncviewer is daemonized.
+    """
     vncargs = (["vncviewer", "-log", "*:stdout:0",
             "-listen", "%d" % (VNC_BASE_PORT + display) ])
-    global vncpid    
-    vncpid = os.spawnvp(os.P_NOWAIT, "vncviewer", vncargs)
-
+    global vncpid
+    vncpid = daemonize("vncviewer", vncargs)
+    if vncpid == 0:
+        return 0
     return VNC_BASE_PORT + display
-    
+
 def preprocess_vnc(vals):
     """If vnc was specified, spawn a vncviewer in listen mode
     and pass its address to the domain on the kernel command line.

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel