[PATCH 2/3] KVM test: virtio_console: Adding SIGIO test

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Sigio was added in kernel 2.6.37.

It was necessary to slightly change structure of virtio_guest,
because the signals coming into the main thread of process.
Signals which arrived in the main thread cancel system call
(os.read and others) and it caused problems

New sructure:
       main thread                    work thread
     wait for signals                   do work

Signed-off-by: Jiri Zupka <jzupka@xxxxxxxxxx>
---
 client/tests/kvm/scripts/virtio_guest.py |  200 ++++++++++++++++++++++++------
 client/tests/kvm/tests/virtio_console.py |   88 ++++++++++++-
 2 files changed, 240 insertions(+), 48 deletions(-)

diff --git a/client/tests/kvm/scripts/virtio_guest.py b/client/tests/kvm/scripts/virtio_guest.py
index bc86624..f8b3650 100755
--- a/client/tests/kvm/scripts/virtio_guest.py
+++ b/client/tests/kvm/scripts/virtio_guest.py
@@ -10,7 +10,7 @@ Auxiliary script used to send data between ports on guests.
 import threading
 from threading import Thread
 import os, time, select, re, random, sys, array
-import fcntl, array, subprocess, traceback
+import fcntl, array, subprocess, traceback, signal
 
 DEBUGPATH = "/sys/kernel/debug"
 SYSFSPATH = "/sys/class/virtio-ports/"
@@ -29,6 +29,8 @@ class VirtioGuest:
         self.exit_thread = threading.Event()
         self.threads = []
         self.ports = {}
+        self.poll_fds = {}
+        self.catch_signal = None
 
 
     def _readfile(self, name):
@@ -253,6 +255,28 @@ class VirtioGuest:
                     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):
         """
@@ -267,37 +291,12 @@ class VirtioGuest:
 
         mask = p.poll(timeout)
 
-        str = ""
-        if (mask[0][1] & select.POLLIN):
-            str += "IN "
-        if (mask[0][1] & select.POLLPRI):
-            str += "PRI IN "
-        if (mask[0][1] & select.POLLOUT):
-            str += "OUT "
-        if (mask[0][1] & select.POLLERR):
-            str += "ERR "
-        if (mask[0][1] & select.POLLHUP):
-            str += "HUP "
-        if (mask[0][1] & select.POLLMSG):
-            str += "MSG "
-
+        maskstr = VirtioGuest.pollmask_to_str(mask[0][1])
         if (mask[0][1] & expected) == expected:
-            print "PASS: Events: " + str
+            print "PASS: Events: " + maskstr
         else:
-            estr = ""
-            if (expected & select.POLLIN):
-                estr += "IN "
-            if (expected & select.POLLPRI):
-                estr += "PRI IN "
-            if (expected & select.POLLOUT):
-                estr += "OUT "
-            if (expected & select.POLLERR):
-                estr += "ERR "
-            if (expected & select.POLLHUP):
-                estr += "HUP "
-            if (expected & select.POLLMSG):
-                estr += "MSG "
-            print "FAIL: Events: " + str + "  Expected: " + estr
+            emaskstr = VirtioGuest.pollmask_to_str(expected)
+            print "FAIL: Events: " + maskstr + "  Expected: " + emaskstr
 
 
     def lseek(self, port, pos, how):
@@ -349,6 +348,104 @@ class VirtioGuest:
             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(10)
+            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)
+            if mode:
+                fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_ASYNC)
+                self.poll_fds[fd] = [exp_val, 0]
+                self.catch_signal = True
+                os.kill(os.getpid(), signal.SIGCONT)
+            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.SIGCONT)
+
+        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.
@@ -526,7 +623,7 @@ def is_alive():
     """
     Check is only main thread is alive and if guest react.
     """
-    if threading.activeCount() == 1:
+    if threading.activeCount() == 2:
         print ("PASS: Guest is ok no thread alive")
     else:
         threads = ""
@@ -542,17 +639,13 @@ def compile():
     import py_compile
     py_compile.compile(sys.path[0] + "/virtio_guest.py")
     print "PASS: compile"
-    exit(0)
+    sys.exit()
 
 
-def main():
+def worker(virt):
     """
-    Main (infinite) loop of virtio_guest.
+    Worker thread (infinite) loop of virtio_guest.
     """
-    if (len(sys.argv) > 1) and (sys.argv[1] == "-c"):
-        compile()
-
-    virt = VirtioGuest()
     print "PASS: Start"
 
     while True:
@@ -562,9 +655,34 @@ def main():
         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))
+                            traceback.format_exception(exc_type,
+                                                       exc_value,
+                                                       exc_traceback))
+    sys.exit(0)
+
+
+def sigcont_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()
+
+    virt = VirtioGuest()
+    slave = Thread(target=worker, args=(virt, ))
+    slave.start()
+    signal.signal(signal.SIGCONT, sigcont_handler)
+    while True:
+        signal.pause()
+        catch = virt.catching_signal()
+        if catch:
+                signal.signal(signal.SIGIO, virt)
+        elif catch == False:
+                signal.signal(signal.SIGIO, signal.SIG_DFL)
 
 
 if __name__ == "__main__":
diff --git a/client/tests/kvm/tests/virtio_console.py b/client/tests/kvm/tests/virtio_console.py
index cf5665b..a7922b1 100644
--- a/client/tests/kvm/tests/virtio_console.py
+++ b/client/tests/kvm/tests/virtio_console.py
@@ -675,6 +675,62 @@ def run_virtio_console(test, params, env):
         on_guest("virt.poll('%s', %s)" % (port.name, select.POLLOUT), vm,
                  2)
 
+
+    def tsigio(vm, port):
+        """
+        Test try sigio function.
+
+        @param vm: Target virtual machine [vm, session, tmp_dir].
+        @param port: Port used in test.
+        """
+        if port.is_open:
+            port.close()
+
+        # Enable sigio on specific port
+        on_guest("virt.async('%s', True, 0)" %
+                 (port.name) , vm, 2)
+        on_guest("virt.get_sigio_poll_return('%s')" % (port.name) , vm, 2)
+
+        #Test sigio when port open
+        on_guest("virt.set_pool_want_return('%s', select.POLLOUT)" %
+                 (port.name), vm, 2)
+        port.open()
+        match = _on_guest("virt.get_sigio_poll_return('%s')" %
+                          (port.name) , vm, 2)[0]
+        if match == 1:
+            raise error.TestFail("Problem with HUP on console port.")
+
+        #Test sigio when port receive data
+        on_guest("virt.set_pool_want_return('%s', select.POLLOUT |"
+                 " select.POLLIN)" % (port.name), vm, 2)
+        port.sock.sendall("0123456789")
+        on_guest("virt.get_sigio_poll_return('%s')" % (port.name) , vm, 2)
+
+        #Test sigio port close event
+        on_guest("virt.set_pool_want_return('%s', select.POLLHUP |"
+                 " select.POLLIN)" % (port.name), vm, 2)
+        port.close()
+        on_guest("virt.get_sigio_poll_return('%s')" % (port.name) , vm, 2)
+
+        #Test sigio port open event and persistence of written data on port.
+        on_guest("virt.set_pool_want_return('%s', select.POLLOUT |"
+                 " select.POLLIN)" % (port.name), vm, 2)
+        port.open()
+        on_guest("virt.get_sigio_poll_return('%s')" % (port.name) , vm, 2)
+
+        #Test event when erase data.
+        on_guest("virt.clean_port('%s')" % (port.name), vm, 2)
+        port.close()
+        on_guest("virt.set_pool_want_return('%s', select.POLLOUT)"
+                 % (port.name), vm, 2)
+        port.open()
+        on_guest("virt.get_sigio_poll_return('%s')" % (port.name) , vm, 2)
+
+        # Disable sigio on specific port
+        on_guest("virt.async('%s', False, 0)" %
+                 (port.name) , vm, 2)
+
+
     def tlseek(vm, port):
         """
         Tests the correct handling of lseek (expected fail)
@@ -832,6 +888,7 @@ def run_virtio_console(test, params, env):
             test.do_test(tclose, [vm, send_pt], True)
             test.do_test(tmulti_open, [vm, send_pt], True)
             test.do_test(tpooling, [vm, send_pt])
+            test.do_test(tsigio, [vm, send_pt])
             test.do_test(tlseek, [vm, send_pt])
             test.do_test(trw_host_offline, [vm, send_pt])
             test.do_test(trw_nonblocking_mode, [vm, send_pt])
@@ -1075,6 +1132,7 @@ def run_virtio_console(test, params, env):
         match, tmp = _on_guest("is_alive()", vm, 10)
         if (match == None) or (match != 0):
             logging.error("Python died/is stucked/have remaining threads")
+            logging.debug(tmp)
             vm[1].close()
             vm[1] = kvm_test_utils.wait_for_login(vm[0], 0,
                                          float(params.get("boot_timeout", 240)),
@@ -1088,18 +1146,33 @@ def run_virtio_console(test, params, env):
                 raise error.TestFail("Python is really stucked - "
                                      "can't kill -9 it")
 
-            on_guest("rmmod -f virtio_console && echo -n PASS: rmmod "
-                     "|| echo -n FAIL: rmmod", vm, 10)
-            on_guest("modprobe virtio_console "
-                     "&& echo -n PASS: modprobe || echo -n FAIL: modprobe",
-                     vm, 10)
+            #on_guest("rmmod -f virtio_console && echo -n PASS: rmmod "
+            #         "|| echo -n FAIL: rmmod", vm, 10)
+            #on_guest("modprobe virtio_console "
+            #         "&& echo -n PASS: modprobe || echo -n FAIL: modprobe",
+            #         vm, 10)
 
             init_guest(vm, consoles)
             (match, data) = _on_guest("virt.clean_port('%s'),1024" %
                                       consoles[0][0].name, vm, 2)
             if (match == None) or (match != 0):
-                raise error.TestFail("Virtio-console driver is irreparably"
-                                     " blocked. Every comd end with sig KILL.")
+                logging.error(data)
+                logging.error("Virtio-console driver is irreparably"
+                              " blocked. Every comd end with sig KILL."
+                              "Try reboot vm for continue in testing.")
+                vm[1] = kvm_test_utils.reboot(vm[0], vm[1], "system_reset")
+                init_guest(vm, consoles)
+                (match, data) = _on_guest("virt.clean_port('%s'),1024" %
+                                      consoles[0][0].name, vm, 2)
+
+                if (match == None) or (match != 0):
+                    raise error.TestFail("Virtio-console driver is irreparably"
+                                         " blocked. Every comd end with sig"
+                                         " KILL. Neither the restart did not"
+                                         " help.")
+            else:
+                on_guest("virt.close('%s'),1024" % consoles[0][0].name, vm, 2)
+
 
         for ctype in consoles:
             for port in ctype:
@@ -1109,6 +1182,7 @@ def run_virtio_console(test, params, env):
                 on_guest("virt.clean_port('%s'),1024" % port.name, vm, 2)
                 if not openned:
                     port.close()
+                    on_guest("virt.close('%s'),1024" % port.name, vm, 2)
 
 
     # INITIALIZE
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux