bitkeeper revision 1.1513.1.1 (42925a6aSZSwfyaVsNzV4psPmpZwZg)

Execute xc_linux_restore in a seperate process so that it can't
crash xend.  Also handle errors passed from xc_linux_restore and
log info messages from xc_linux_restore.
XendDomain.py:
  Popen xc_restore instead of calling xc_linux_restore directly.
xc.c:
  Add pyxc_handle exporting the file descriptor to the control interface.
  Remove xc_linux_restore -- replaced by popen of xc_restore directly
  from python.
xc_linux_restore.c:
  Enable debug output.
xpopen.py:
  Add xpopen functionality:
  Optionally exclude a list of file descriptors from being closed, allowing
  access to those file descriptors from the command.
  Remove unused parts.
xpopen.py, Makefile, xc_restore.c:
  new file
Makefile:
  Add xcutils subdir.
ignore:
  Add tools/xcutils/xc_restore.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
This commit is contained in:
cl349@firebug.cl.cam.ac.uk committed 2005-05-23 22:34:18 +00:00
1 parent dad197b071
commit 35db9d71b6
9 files changed
+251 -41

No files matched your search

+12 -38
View File
@@ -63,6 +63,13 @@ static PyObject *pyxc_domain_dumpcore(PyObject *self,
return NULL;
}
static PyObject *pyxc_handle(PyObject *self)
{
XcObject *xc = (XcObject *)self;
return PyInt_FromLong(xc->xc_handle);
}
static PyObject *pyxc_domain_create(PyObject *self,
PyObject *args,
PyObject *kwds)
@@ -334,36 +341,6 @@ static PyObject *pyxc_linux_save(PyObject *self,
return val;
}
static PyObject *pyxc_linux_restore(PyObject *self,
PyObject *args,
PyObject *kwds)
{
XcObject *xc = (XcObject *)self;
PyObject *val = NULL;
int rc =-1;
int io_fd, dom;
unsigned long nr_pfns;
static char *kwd_list[] = { "fd", "dom", "pfns", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iil", kwd_list,
&io_fd, &dom, &nr_pfns) )
goto exit;
rc = xc_linux_restore(xc->xc_handle, io_fd, dom, nr_pfns);
if ( rc != 0 )
{
PyErr_SetFromErrno(xc_error);
goto exit;
}
Py_INCREF(zero);
val = zero;
exit:
return val;
}
static PyObject *pyxc_linux_build(PyObject *self,
PyObject *args,
PyObject *kwds)
@@ -938,6 +915,11 @@ static PyObject *pyxc_domain_memory_increase_reservation(PyObject *self,
static PyMethodDef pyxc_methods[] = {
{ "handle",
(PyCFunction)pyxc_handle,
0, "\n"
"Query the xc control interface file descriptor.\n\n"
"Returns: [int] file descriptor\n" },
{ "domain_create",
(PyCFunction)pyxc_domain_create,
METH_VARARGS | METH_KEYWORDS, "\n"
@@ -1026,14 +1008,6 @@ static PyMethodDef pyxc_methods[] = {
" progress [int, 1]: Bool - display a running progress indication?\n\n"
"Returns: [int] 0 on success; -1 on error.\n" },
{ "linux_restore",
(PyCFunction)pyxc_linux_restore,
METH_VARARGS | METH_KEYWORDS, "\n"
"Restore the CPU and memory state of a Linux guest OS.\n"
" dom [int]: Identifier of domain to be restored.\n"
" pfns [int]: Number of pages domain uses.\n"
"Returns: [int] new domain identifier on success; -1 on error.\n" },
{ "linux_build",
(PyCFunction)pyxc_linux_build,
METH_VARARGS | METH_KEYWORDS, "\n"
+112
View File
@@ -0,0 +1,112 @@
"""Spawn a command with pipes to its stdin, stdout, and optionally stderr.
The normal os.popen(cmd, mode) call spawns a shell command and provides a
file interface to just the input or output of the process depending on
whether mode is 'r' or 'w'. This module provides the functions xpopen2(cmd)
and xpopen3(cmd) which return two or three pipes to the spawned command.
Optionally exclude a list of file descriptors from being closed, allowing
access to those file descriptors from the command.
"""
import os
import sys
try:
MAXFD = os.sysconf('SC_OPEN_MAX')
except (AttributeError, ValueError):
MAXFD = 256
_active = []
def _cleanup():
for inst in _active[:]:
inst.poll()
class xPopen3:
"""Class representing a child process. Normally instances are created
by the factory functions popen2() and popen3()."""
sts = -1 # Child not completed yet
def __init__(self, cmd, capturestderr=False, bufsize=-1, passfd=()):
"""The parameter 'cmd' is the shell command to execute in a
sub-process. The 'capturestderr' flag, if true, specifies that
the object should capture standard error output of the child process.
The default is false. If the 'bufsize' parameter is specified, it
specifies the size of the I/O buffers to/from the child process."""
_cleanup()
self.passfd = passfd
p2cread, p2cwrite = os.pipe()
c2pread, c2pwrite = os.pipe()
if capturestderr:
errout, errin = os.pipe()
self.pid = os.fork()
if self.pid == 0:
# Child
os.dup2(p2cread, 0)
os.dup2(c2pwrite, 1)
if capturestderr:
os.dup2(errin, 2)
self._run_child(cmd)
os.close(p2cread)
self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
os.close(c2pwrite)
self.fromchild = os.fdopen(c2pread, 'r', bufsize)
if capturestderr:
os.close(errin)
self.childerr = os.fdopen(errout, 'r', bufsize)
else:
self.childerr = None
_active.append(self)
def _run_child(self, cmd):
if isinstance(cmd, basestring):
cmd = ['/bin/sh', '-c', cmd]
for i in range(3, MAXFD):
if i in self.passfd:
continue
try:
os.close(i)
except OSError:
pass
try:
os.execvp(cmd[0], cmd)
finally:
os._exit(1)
def poll(self):
"""Return the exit status of the child process if it has finished,
or -1 if it hasn't finished yet."""
if self.sts < 0:
try:
pid, sts = os.waitpid(self.pid, os.WNOHANG)
if pid == self.pid:
self.sts = sts
_active.remove(self)
except os.error:
pass
return self.sts
def wait(self):
"""Wait for and return the exit status of the child process."""
if self.sts < 0:
pid, sts = os.waitpid(self.pid, 0)
if pid == self.pid:
self.sts = sts
_active.remove(self)
return self.sts
def xpopen2(cmd, bufsize=-1, mode='t', passfd=[]):
"""Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
specified, it sets the buffer size for the I/O pipes. The file objects
(child_stdout, child_stdin) are returned."""
inst = xPopen3(cmd, False, bufsize, passfd)
return inst.fromchild, inst.tochild
def xpopen3(cmd, bufsize=-1, mode='t', passfd=[]):
"""Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
specified, it sets the buffer size for the I/O pipes. The file objects
(child_stdout, child_stdin, child_stderr) are returned."""
inst = xPopen3(cmd, True, bufsize, passfd)
return inst.fromchild, inst.tochild, inst.childerr
+28 -1
View File
@@ -25,7 +25,11 @@ from xen.xend.server import channel
import errno
import os
import select
from string import join
from struct import pack, unpack, calcsize
from xen.util.xpopen import xPopen3
__all__ = [ "XendDomain" ]
@@ -325,6 +329,7 @@ class XendDomain:
sizeof_int = calcsize("i")
sizeof_unsigned_long = calcsize("L")
PAGE_SIZE = 4096
PATH_XC_RESTORE = "/usr/libexec/xen/xc_restore"
class XendFile(file):
def read_exact(self, size, error_msg):
@@ -367,7 +372,29 @@ class XendDomain:
# underlying file descriptor
ignore = fd.tell()
xc.linux_restore(fd.fileno(), int(dominfo.id), nr_pfns)
cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd.fileno()),
dominfo.id, str(nr_pfns)]
log.info("[xc_restore] " + join(cmd))
child = xPopen3(cmd, True, -1, [fd.fileno(), xc.handle()])
child.tochild.close()
lasterr = ""
p = select.poll()
p.register(child.fromchild.fileno())
p.register(child.childerr.fileno())
while True:
r = p.poll()
for l in child.childerr.readlines():
log.error(l.rstrip())
lasterr = l.rstrip()
for l in child.fromchild.readlines():
log.info(l.rstrip())
if filter(lambda (fd, event): event & select.POLLHUP, r):
break
if child.wait() != 0:
raise XendError("xc_restore failed: %s" % lasterr)
return dominfo
except IOError, ex:
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.