| Index: client/tests/kvm/scripts/virtio_console_guest.py
 | 
| diff --git a/client/tests/kvm/scripts/virtio_console_guest.py b/client/tests/kvm/scripts/virtio_console_guest.py
 | 
| new file mode 100755
 | 
| index 0000000000000000000000000000000000000000..c407231aab3523ebf00bfa51beed08e9a99c89ba
 | 
| --- /dev/null
 | 
| +++ b/client/tests/kvm/scripts/virtio_console_guest.py
 | 
| @@ -0,0 +1,715 @@
 | 
| +#!/usr/bin/python
 | 
| +# -*- coding: utf-8 -*-
 | 
| +"""
 | 
| +Auxiliary script used to send data between ports on guests.
 | 
| +
 | 
| +@copyright: 2010 Red Hat, Inc.
 | 
| +@author: Jiri Zupka (jzupka@redhat.com)
 | 
| +@author: Lukas Doktor (ldoktor@redhat.com)
 | 
| +"""
 | 
| +import threading
 | 
| +from threading import Thread
 | 
| +import os, select, re, random, sys, array
 | 
| +import fcntl, traceback, signal
 | 
| +
 | 
| +DEBUGPATH = "/sys/kernel/debug"
 | 
| +SYSFSPATH = "/sys/class/virtio-ports/"
 | 
| +
 | 
| +exiting = False
 | 
| +
 | 
| +class VirtioGuest:
 | 
| +    """
 | 
| +    Test tools of virtio_ports.
 | 
| +    """
 | 
| +    LOOP_NONE = 0
 | 
| +    LOOP_POLL = 1
 | 
| +    LOOP_SELECT = 2
 | 
| +
 | 
| +    def __init__(self):
 | 
| +        self.files = {}
 | 
| +        self.exit_thread = threading.Event()
 | 
| +        self.threads = []
 | 
| +        self.ports = {}
 | 
| +        self.poll_fds = {}
 | 
| +        self.catch_signal = None
 | 
| +        self.use_config = threading.Event()
 | 
| +
 | 
| +
 | 
| +    def _readfile(self, name):
 | 
| +        """
 | 
| +        Read file and return content as string
 | 
| +
 | 
| +        @param name: Name of file
 | 
| +        @return: Content of file as string
 | 
| +        """
 | 
| +        out = ""
 | 
| +        try:
 | 
| +            f = open(name, "r")
 | 
| +            out = f.read()
 | 
| +            f.close()
 | 
| +        except:
 | 
| +            print "FAIL: Cannot open file %s" % (name)
 | 
| +
 | 
| +        return out
 | 
| +
 | 
| +
 | 
| +    def _get_port_status(self):
 | 
| +        """
 | 
| +        Get info about ports from kernel debugfs.
 | 
| +
 | 
| +        @return: Ports dictionary of port properties
 | 
| +        """
 | 
| +        ports = {}
 | 
| +        not_present_msg = "FAIL: There's no virtio-ports dir in debugfs"
 | 
| +        if (not os.path.ismount(DEBUGPATH)):
 | 
| +            os.system('mount -t debugfs none %s' % (DEBUGPATH))
 | 
| +        try:
 | 
| +            if not os.path.isdir('%s/virtio-ports' % (DEBUGPATH)):
 | 
| +                print not_present_msg
 | 
| +        except:
 | 
| +            print not_present_msg
 | 
| +        else:
 | 
| +            viop_names = os.listdir('%s/virtio-ports' % (DEBUGPATH))
 | 
| +            for name in viop_names:
 | 
| +                open_db_file = "%s/virtio-ports/%s" % (DEBUGPATH, name)
 | 
| +                f = open(open_db_file, 'r')
 | 
| +                port = {}
 | 
| +                file = []
 | 
| +                for line in iter(f):
 | 
| +                    file.append(line)
 | 
| +                try:
 | 
| +                    for line in file:
 | 
| +                        m = re.match("(\S+): (\S+)", line)
 | 
| +                        port[m.group(1)] = m.group(2)
 | 
| +
 | 
| +                    if (port['is_console'] == "yes"):
 | 
| +                        port["path"] = "/dev/hvc%s" % (port["console_vtermno"])
 | 
| +                        # Console works like a serialport
 | 
| +                    else:
 | 
| +                        port["path"] = "/dev/%s" % name
 | 
| +
 | 
| +                    if (not os.path.exists(port['path'])):
 | 
| +                        print "FAIL: %s not exist" % port['path']
 | 
| +
 | 
| +                    sysfspath = SYSFSPATH + name
 | 
| +                    if (not os.path.isdir(sysfspath)):
 | 
| +                        print "FAIL: %s not exist" % (sysfspath)
 | 
| +
 | 
| +                    info_name = sysfspath + "/name"
 | 
| +                    port_name = self._readfile(info_name).strip()
 | 
| +                    if (port_name != port["name"]):
 | 
| +                        print ("FAIL: Port info not match \n%s - %s\n%s - %s" %
 | 
| +                               (info_name , port_name,
 | 
| +                                "%s/virtio-ports/%s" % (DEBUGPATH, name),
 | 
| +                                port["name"]))
 | 
| +                except AttributeError:
 | 
| +                    print ("In file " + open_db_file +
 | 
| +                           " are bad data\n"+ "".join(file).strip())
 | 
| +                    print ("FAIL: Fail file data.")
 | 
| +                    return
 | 
| +
 | 
| +                ports[port['name']] = port
 | 
| +                f.close()
 | 
| +
 | 
| +        return ports
 | 
| +
 | 
| +
 | 
| +    def init(self, in_files):
 | 
| +        """
 | 
| +        Init and check port properties.
 | 
| +        """
 | 
| +        self.ports = self._get_port_status()
 | 
| +
 | 
| +        if self.ports == None:
 | 
| +            return
 | 
| +        for item in in_files:
 | 
| +            if (item[1] != self.ports[item[0]]["is_console"]):
 | 
| +                print self.ports
 | 
| +                print "FAIL: Host console is not like console on guest side\n"
 | 
| +        print "PASS: Init and check virtioconsole files in system."
 | 
| +
 | 
| +
 | 
| +    class Switch(Thread):
 | 
| +        """
 | 
| +        Thread that sends data between ports.
 | 
| +        """
 | 
| +        def __init__ (self, in_files, out_files, event,
 | 
| +                      cachesize=1024, method=0):
 | 
| +            """
 | 
| +            @param in_files: Array of input files.
 | 
| +            @param out_files: Array of output files.
 | 
| +            @param method: Method of read/write access.
 | 
| +            @param cachesize: Block to receive and send.
 | 
| +            """
 | 
| +            Thread.__init__(self, name="Switch")
 | 
| +
 | 
| +            self.in_files = in_files
 | 
| +            self.out_files = out_files
 | 
| +            self.exit_thread = event
 | 
| +            self.method = method
 | 
| +
 | 
| +            self.cachesize = cachesize
 | 
| +
 | 
| +
 | 
| +        def _none_mode(self):
 | 
| +            """
 | 
| +            Read and write to device in blocking mode
 | 
| +            """
 | 
| +            data = ""
 | 
| +            while not self.exit_thread.isSet():
 | 
| +                data = ""
 | 
| +                for desc in self.in_files:
 | 
| +                    data += os.read(desc, self.cachesize)
 | 
| +                if data != "":
 | 
| +                    for desc in self.out_files:
 | 
| +                        os.write(desc, data)
 | 
| +
 | 
| +
 | 
| +        def _poll_mode(self):
 | 
| +            """
 | 
| +            Read and write to device in polling mode.
 | 
| +            """
 | 
| +
 | 
| +            pi = select.poll()
 | 
| +            po = select.poll()
 | 
| +
 | 
| +            for fd in self.in_files:
 | 
| +                pi.register(fd, select.POLLIN)
 | 
| +
 | 
| +            for fd in self.out_files:
 | 
| +                po.register(fd, select.POLLOUT)
 | 
| +
 | 
| +            while not self.exit_thread.isSet():
 | 
| +                data = ""
 | 
| +                t_out = self.out_files
 | 
| +
 | 
| +                readyf = pi.poll(1.0)
 | 
| +                for i in readyf:
 | 
| +                    data += os.read(i[0], self.cachesize)
 | 
| +
 | 
| +                if data != "":
 | 
| +                    while ((len(t_out) != len(readyf)) and not
 | 
| +                           self.exit_thread.isSet()):
 | 
| +                        readyf = po.poll(1.0)
 | 
| +                    for desc in t_out:
 | 
| +                        os.write(desc, data)
 | 
| +
 | 
| +
 | 
| +        def _select_mode(self):
 | 
| +            """
 | 
| +            Read and write to device in selecting mode.
 | 
| +            """
 | 
| +            while not self.exit_thread.isSet():
 | 
| +                ret = select.select(self.in_files, [], [], 1.0)
 | 
| +                data = ""
 | 
| +                if ret[0] != []:
 | 
| +                    for desc in ret[0]:
 | 
| +                        data += os.read(desc, self.cachesize)
 | 
| +                if data != "":
 | 
| +                    ret = select.select([], self.out_files, [], 1.0)
 | 
| +                    while ((len(self.out_files) != len(ret[1])) and not
 | 
| +                           self.exit_thread.isSet()):
 | 
| +                        ret = select.select([], self.out_files, [], 1.0)
 | 
| +                    for desc in ret[1]:
 | 
| +                        os.write(desc, data)
 | 
| +
 | 
| +
 | 
| +        def run(self):
 | 
| +            if (self.method == VirtioGuest.LOOP_POLL):
 | 
| +                self._poll_mode()
 | 
| +            elif (self.method == VirtioGuest.LOOP_SELECT):
 | 
| +                self._select_mode()
 | 
| +            else:
 | 
| +                self._none_mode()
 | 
| +
 | 
| +
 | 
| +    class Sender(Thread):
 | 
| +        """
 | 
| +        Creates a thread which sends random blocks of data to dst port.
 | 
| +        """
 | 
| +        def __init__(self, port, event, length):
 | 
| +            """
 | 
| +            @param port: Destination port
 | 
| +            @param length: Length of the random data block
 | 
| +            """
 | 
| +            Thread.__init__(self, name="Sender")
 | 
| +            self.port = port
 | 
| +            self.exit_thread = event
 | 
| +            self.data = array.array('L')
 | 
| +            for i in range(max(length / self.data.itemsize, 1)):
 | 
| +                self.data.append(random.randrange(sys.maxint))
 | 
| +
 | 
| +        def run(self):
 | 
| +            while not self.exit_thread.isSet():
 | 
| +                os.write(self.port, self.data)
 | 
| +
 | 
| +
 | 
| +    def _open(self, in_files):
 | 
| +        """
 | 
| +        Open devices and return array of descriptors
 | 
| +
 | 
| +        @param in_files: Files array
 | 
| +        @return: Array of descriptor
 | 
| +        """
 | 
| +        f = []
 | 
| +
 | 
| +        for item in in_files:
 | 
| +            name = self.ports[item]["path"]
 | 
| +            if (name in self.files):
 | 
| +                f.append(self.files[name])
 | 
| +            else:
 | 
| +                try:
 | 
| +                    self.files[name] = os.open(name, os.O_RDWR)
 | 
| +                    if (self.ports[item]["is_console"] == "yes"):
 | 
| +                        print os.system("stty -F %s raw -echo" % (name))
 | 
| +                        print os.system("stty -F %s -a" % (name))
 | 
| +                    f.append(self.files[name])
 | 
| +                except Exception, inst:
 | 
| +                    print "FAIL: Failed to open file %s" % (name)
 | 
| +                    raise inst
 | 
| +        return f
 | 
| +
 | 
| +    @staticmethod
 | 
| +    def pollmask_to_str(mask):
 | 
| +        """
 | 
| +        Conver pool mast to string
 | 
| +
 | 
| +        @param mask: poll return mask
 | 
| +        """
 | 
| +        str = ""
 | 
| +        if (mask & select.POLLIN):
 | 
| +            str += "IN "
 | 
| +        if (mask & select.POLLPRI):
 | 
| +            str += "PRI IN "
 | 
| +        if (mask & select.POLLOUT):
 | 
| +            str += "OUT "
 | 
| +        if (mask & select.POLLERR):
 | 
| +            str += "ERR "
 | 
| +        if (mask & select.POLLHUP):
 | 
| +            str += "HUP "
 | 
| +        if (mask & select.POLLMSG):
 | 
| +            str += "MSG "
 | 
| +        return str
 | 
| +
 | 
| +
 | 
| +    def poll(self, port, expected, timeout=500):
 | 
| +        """
 | 
| +        Pool event from device and print event like text.
 | 
| +
 | 
| +        @param file: Device.
 | 
| +        """
 | 
| +        in_f = self._open([port])
 | 
| +
 | 
| +        p = select.poll()
 | 
| +        p.register(in_f[0])
 | 
| +
 | 
| +        mask = p.poll(timeout)
 | 
| +
 | 
| +        maskstr = VirtioGuest.pollmask_to_str(mask[0][1])
 | 
| +        if (mask[0][1] & expected) == expected:
 | 
| +            print "PASS: Events: " + maskstr
 | 
| +        else:
 | 
| +            emaskstr = VirtioGuest.pollmask_to_str(expected)
 | 
| +            print "FAIL: Events: " + maskstr + "  Expected: " + emaskstr
 | 
| +
 | 
| +
 | 
| +    def lseek(self, port, pos, how):
 | 
| +        """
 | 
| +        Use lseek on the device. The device is unseekable so PASS is returned
 | 
| +        when lseek command fails and vice versa.
 | 
| +
 | 
| +        @param port: Name of the port
 | 
| +        @param pos: Offset
 | 
| +        @param how: Relativ offset os.SEEK_{SET,CUR,END}
 | 
| +        """
 | 
| +        fd = self._open([port])[0]
 | 
| +
 | 
| +        try:
 | 
| +            os.lseek(fd, pos, how)
 | 
| +        except Exception, inst:
 | 
| +            if inst.errno == 29:
 | 
| +                print "PASS: the lseek failed as expected"
 | 
| +            else:
 | 
| +                print inst
 | 
| +                print "FAIL: unknown error"
 | 
| +        else:
 | 
| +            print "FAIL: the lseek unexpectedly passed"
 | 
| +
 | 
| +
 | 
| +    def blocking(self, port, mode=False):
 | 
| +        """
 | 
| +        Set port function mode blocking/nonblocking
 | 
| +
 | 
| +        @param port: port to set mode
 | 
| +        @param mode: False to set nonblock mode, True for block mode
 | 
| +        """
 | 
| +        fd = self._open([port])[0]
 | 
| +
 | 
| +        try:
 | 
| +            fl = fcntl.fcntl(fd, fcntl.F_GETFL)
 | 
| +            if not mode:
 | 
| +                fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
 | 
| +            else:
 | 
| +                fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK)
 | 
| +
 | 
| +        except Exception, inst:
 | 
| +            print "FAIL: Setting (non)blocking mode: " + str(inst)
 | 
| +            return
 | 
| +
 | 
| +        if mode:
 | 
| +            print "PASS: set to blocking mode"
 | 
| +        else:
 | 
| +            print "PASS: set to nonblocking mode"
 | 
| +
 | 
| +
 | 
| +    def __call__(self, sig, frame):
 | 
| +        """
 | 
| +        Call function. Used for signal handle.
 | 
| +        """
 | 
| +        if (sig == signal.SIGIO):
 | 
| +            self.sigio_handler(sig, frame)
 | 
| +
 | 
| +
 | 
| +    def sigio_handler(self, sig, frame):
 | 
| +        """
 | 
| +        Handler for sigio operation.
 | 
| +
 | 
| +        @param sig: signal which call handler.
 | 
| +        @param frame: frame of caller
 | 
| +        """
 | 
| +        if self.poll_fds:
 | 
| +            p = select.poll()
 | 
| +            map(p.register, self.poll_fds.keys())
 | 
| +
 | 
| +            masks = p.poll(1)
 | 
| +            print masks
 | 
| +            for mask in masks:
 | 
| +                self.poll_fds[mask[0]][1] |= mask[1]
 | 
| +
 | 
| +
 | 
| +    def get_sigio_poll_return(self, port):
 | 
| +        """
 | 
| +        Return PASS, FAIL and poll walue in string format.
 | 
| +
 | 
| +        @param port: Port to check poll information.
 | 
| +        """
 | 
| +        fd = self._open([port])[0]
 | 
| +
 | 
| +        maskstr = VirtioGuest.pollmask_to_str(self.poll_fds[fd][1])
 | 
| +        if (self.poll_fds[fd][0] ^ self.poll_fds[fd][1]):
 | 
| +            emaskstr = VirtioGuest.pollmask_to_str(self.poll_fds[fd][0])
 | 
| +            print "FAIL: Events: " + maskstr + "  Expected: " + emaskstr
 | 
| +        else:
 | 
| +            print "PASS: Events: " + maskstr
 | 
| +        self.poll_fds[fd][1] = 0
 | 
| +
 | 
| +
 | 
| +    def set_pool_want_return(self, port, poll_value):
 | 
| +        """
 | 
| +        Set value to static variable.
 | 
| +
 | 
| +        @param port: Port which should be set excepted mask
 | 
| +        @param poll_value: Value to check sigio signal.
 | 
| +        """
 | 
| +        fd = self._open([port])[0]
 | 
| +        self.poll_fds[fd] = [poll_value, 0]
 | 
| +        print "PASS: Events: " + VirtioGuest.pollmask_to_str(poll_value)
 | 
| +
 | 
| +
 | 
| +    def catching_signal(self):
 | 
| +        """
 | 
| +        return: True if should set catch signal, False if ignore signal and
 | 
| +                none when configuration is not changed.
 | 
| +        """
 | 
| +        ret = self.catch_signal
 | 
| +        self.catch_signal = None
 | 
| +        return ret
 | 
| +
 | 
| +
 | 
| +    def async(self, port, mode=True, exp_val = 0):
 | 
| +        """
 | 
| +        Set port function mode async/sync.
 | 
| +
 | 
| +        @param port: port which should be pooled.
 | 
| +        @param mode: False to set sync mode, True for sync mode.
 | 
| +        @param exp_val: Value which should be pooled.
 | 
| +        """
 | 
| +        fd = self._open([port])[0]
 | 
| +
 | 
| +        try:
 | 
| +            fcntl.fcntl(fd, fcntl.F_SETOWN, os.getpid())
 | 
| +            fl = fcntl.fcntl(fd, fcntl.F_GETFL)
 | 
| +
 | 
| +            self.use_config.clear()
 | 
| +            if mode:
 | 
| +                fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_ASYNC)
 | 
| +                self.poll_fds[fd] = [exp_val, 0]
 | 
| +                self.catch_signal = True
 | 
| +            else:
 | 
| +                del self.poll_fds[fd]
 | 
| +                fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_ASYNC)
 | 
| +                self.catch_signal = False
 | 
| +
 | 
| +            os.kill(os.getpid(), signal.SIGUSR1)
 | 
| +            self.use_config.wait()
 | 
| +
 | 
| +        except Exception, inst:
 | 
| +            print "FAIL: Setting (a)sync mode: " + str(inst)
 | 
| +            return
 | 
| +
 | 
| +        if mode:
 | 
| +            print "PASS: Set to async mode"
 | 
| +        else:
 | 
| +            print "PASS: Set to sync mode"
 | 
| +
 | 
| +
 | 
| +    def close(self, file):
 | 
| +        """
 | 
| +        Close open port.
 | 
| +
 | 
| +        @param file: File to close.
 | 
| +        """
 | 
| +        descriptor = None
 | 
| +        path = self.ports[file]["path"]
 | 
| +        if path != None:
 | 
| +            if path in self.files.keys():
 | 
| +                descriptor = self.files[path]
 | 
| +                del self.files[path]
 | 
| +            if descriptor != None:
 | 
| +                try:
 | 
| +                    os.close(descriptor)
 | 
| +                except Exception, inst:
 | 
| +                    print "FAIL: Closing the file: " + str(inst)
 | 
| +                    return
 | 
| +        print "PASS: Close"
 | 
| +
 | 
| +
 | 
| +    def open(self, in_file):
 | 
| +        """
 | 
| +        Direct open devices.
 | 
| +
 | 
| +        @param in_file: Array of files.
 | 
| +        @return: Array of descriptors.
 | 
| +        """
 | 
| +        name = self.ports[in_file]["path"]
 | 
| +        try:
 | 
| +            self.files[name] = os.open(name, os.O_RDWR)
 | 
| +            if (self.ports[in_file]["is_console"] == "yes"):
 | 
| +                print os.system("stty -F %s raw -echo" % (name))
 | 
| +            print "PASS: Open all filles correctly."
 | 
| +        except Exception, inst:
 | 
| +            print "%s\nFAIL: Failed open file %s" % (str(inst), name)
 | 
| +
 | 
| +
 | 
| +    def loopback(self, in_files, out_files, cachesize=1024, mode=LOOP_NONE):
 | 
| +        """
 | 
| +        Start a switch thread.
 | 
| +
 | 
| +        (There is a problem with multiple opens of a single file).
 | 
| +
 | 
| +        @param in_files: Array of input files.
 | 
| +        @param out_files: Array of output files.
 | 
| +        @param cachesize: Cachesize.
 | 
| +        """
 | 
| +        self.ports = self._get_port_status()
 | 
| +
 | 
| +        in_f = self._open(in_files)
 | 
| +        out_f = self._open(out_files)
 | 
| +
 | 
| +        s = self.Switch(in_f, out_f, self.exit_thread, cachesize, mode)
 | 
| +        s.start()
 | 
| +        self.threads.append(s)
 | 
| +        print "PASS: Start switch"
 | 
| +
 | 
| +
 | 
| +    def exit_threads(self):
 | 
| +        """
 | 
| +        Function end all running data switch.
 | 
| +        """
 | 
| +        self.exit_thread.set()
 | 
| +        for th in self.threads:
 | 
| +            print "join"
 | 
| +            th.join()
 | 
| +        self.exit_thread.clear()
 | 
| +
 | 
| +        del self.threads[:]
 | 
| +        for desc in self.files.itervalues():
 | 
| +            os.close(desc)
 | 
| +        self.files.clear()
 | 
| +        print "PASS: All threads finished."
 | 
| +
 | 
| +
 | 
| +    def die(self):
 | 
| +        """
 | 
| +        Quit consoleswitch.
 | 
| +        """
 | 
| +        self.exit_threads()
 | 
| +        exit()
 | 
| +
 | 
| +
 | 
| +    def send_loop_init(self, port, length):
 | 
| +        """
 | 
| +        Prepares the sender thread. Requires clean thread structure.
 | 
| +        """
 | 
| +        self.ports = self._get_port_status()
 | 
| +        in_f = self._open([port])
 | 
| +
 | 
| +        self.threads.append(self.Sender(in_f[0], self.exit_thread, length))
 | 
| +        print "PASS: Sender prepare"
 | 
| +
 | 
| +
 | 
| +    def send_loop(self):
 | 
| +        """
 | 
| +        Start sender data transfer. Requires senderprepare run first.
 | 
| +        """
 | 
| +        self.threads[0].start()
 | 
| +        print "PASS: Sender start"
 | 
| +
 | 
| +
 | 
| +    def send(self, port, length=1, mode=True):
 | 
| +        """
 | 
| +        Send a data of some length
 | 
| +
 | 
| +        @param port: Port to write data
 | 
| +        @param length: Length of data
 | 
| +        @param mode: True = loop mode, False = one shoot mode
 | 
| +        """
 | 
| +        in_f = self._open([port])
 | 
| +
 | 
| +        data = ""
 | 
| +        while len(data) < length:
 | 
| +            data += "%c" % random.randrange(255)
 | 
| +        try:
 | 
| +            writes = os.write(in_f[0], data)
 | 
| +        except Exception, inst:
 | 
| +            print inst
 | 
| +        if not writes:
 | 
| +            writes = 0
 | 
| +        if mode:
 | 
| +            while (writes < length):
 | 
| +                try:
 | 
| +                    writes += os.write(in_f[0], data)
 | 
| +                except Exception, inst:
 | 
| +                    print inst
 | 
| +        if writes >= length:
 | 
| +            print "PASS: Send data length %d" % writes
 | 
| +        else:
 | 
| +            print ("FAIL: Partial send: desired %d, transfered %d" %
 | 
| +                   (length, writes))
 | 
| +
 | 
| +
 | 
| +    def recv(self, port, length=1, buffer=1024, mode=True):
 | 
| +        """
 | 
| +        Recv a data of some length
 | 
| +
 | 
| +        @param port: Port to write data
 | 
| +        @param length: Length of data
 | 
| +        @param mode: True = loop mode, False = one shoot mode
 | 
| +        """
 | 
| +        in_f = self._open([port])
 | 
| +
 | 
| +        recvs = ""
 | 
| +        try:
 | 
| +            recvs = os.read(in_f[0], buffer)
 | 
| +        except Exception, inst:
 | 
| +            print inst
 | 
| +        if mode:
 | 
| +            while (len(recvs) < length):
 | 
| +                try:
 | 
| +                    recvs += os.read(in_f[0], buffer)
 | 
| +                except Exception, inst:
 | 
| +                    print inst
 | 
| +        if len(recvs) >= length:
 | 
| +            print "PASS: Recv data length %d" % len(recvs)
 | 
| +        else:
 | 
| +            print ("FAIL: Partial recv: desired %d, transfered %d" %
 | 
| +                   (length, len(recvs)))
 | 
| +
 | 
| +
 | 
| +    def clean_port(self, port, buffer=1024):
 | 
| +        in_f = self._open([port])
 | 
| +        ret = select.select([in_f[0]], [], [], 1.0)
 | 
| +        buf = ""
 | 
| +        if ret[0]:
 | 
| +            buf = os.read(in_f[0], buffer)
 | 
| +        print ("PASS: Rest in socket: ") + str(buf[10])
 | 
| +
 | 
| +
 | 
| +def is_alive():
 | 
| +    """
 | 
| +    Check is only main thread is alive and if guest react.
 | 
| +    """
 | 
| +    if threading.activeCount() == 2:
 | 
| +        print ("PASS: Guest is ok no thread alive")
 | 
| +    else:
 | 
| +        threads = ""
 | 
| +        for thread in threading.enumerate():
 | 
| +            threads += thread.name + ", "
 | 
| +        print ("FAIL: On guest run thread. Active thread:" + threads)
 | 
| +
 | 
| +
 | 
| +def compile():
 | 
| +    """
 | 
| +    Compile virtio_console_guest.py to speed up.
 | 
| +    """
 | 
| +    import py_compile
 | 
| +    py_compile.compile(sys.path[0] + "/virtio_console_guest.py")
 | 
| +    print "PASS: compile"
 | 
| +    sys.exit()
 | 
| +
 | 
| +
 | 
| +def guest_exit():
 | 
| +    global exiting
 | 
| +    exiting = True
 | 
| +    os.kill(os.getpid(), signal.SIGUSR1)
 | 
| +
 | 
| +
 | 
| +def worker(virt):
 | 
| +    """
 | 
| +    Worker thread (infinite) loop of virtio_guest.
 | 
| +    """
 | 
| +    global exiting
 | 
| +    print "PASS: Start"
 | 
| +
 | 
| +    while not exiting:
 | 
| +        str = raw_input()
 | 
| +        try:
 | 
| +            exec str
 | 
| +        except:
 | 
| +            exc_type, exc_value, exc_traceback = sys.exc_info()
 | 
| +            print "On Guest exception from: \n" + "".join(
 | 
| +                            traceback.format_exception(exc_type,
 | 
| +                                                       exc_value,
 | 
| +                                                       exc_traceback))
 | 
| +
 | 
| +
 | 
| +def sigusr_handler(sig, frame):
 | 
| +    pass
 | 
| +
 | 
| +
 | 
| +def main():
 | 
| +    """
 | 
| +    Main function with infinite loop to catch signal from system.
 | 
| +    """
 | 
| +    if (len(sys.argv) > 1) and (sys.argv[1] == "-c"):
 | 
| +        compile()
 | 
| +
 | 
| +    global exiting
 | 
| +    virt = VirtioGuest()
 | 
| +    slave = Thread(target=worker, args=(virt, ))
 | 
| +    slave.start()
 | 
| +    signal.signal(signal.SIGUSR1, sigusr_handler)
 | 
| +    while not exiting:
 | 
| +        signal.pause()
 | 
| +        catch = virt.catching_signal()
 | 
| +        if catch:
 | 
| +            signal.signal(signal.SIGIO, virt)
 | 
| +        elif catch == False:
 | 
| +            signal.signal(signal.SIGIO, signal.SIG_DFL)
 | 
| +        if (catch != None):
 | 
| +            virt.use_config.set()
 | 
| +    print "PASS: guest_exit"
 | 
| +
 | 
| +
 | 
| +if __name__ == "__main__":
 | 
| +    main()
 | 
| 
 |