summaryrefslogtreecommitdiffstats
path: root/meta/lib/oeqa/utils/qemurunner.py
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/oeqa/utils/qemurunner.py')
-rw-r--r--meta/lib/oeqa/utils/qemurunner.py54
1 files changed, 32 insertions, 22 deletions
diff --git a/meta/lib/oeqa/utils/qemurunner.py b/meta/lib/oeqa/utils/qemurunner.py
index ee36707800..cdd0db5877 100644
--- a/meta/lib/oeqa/utils/qemurunner.py
+++ b/meta/lib/oeqa/utils/qemurunner.py
@@ -29,6 +29,15 @@ control_chars = [chr(x) for x in control_range
29 if chr(x) not in string.printable] 29 if chr(x) not in string.printable]
30re_control_char = re.compile('[%s]' % re.escape("".join(control_chars))) 30re_control_char = re.compile('[%s]' % re.escape("".join(control_chars)))
31 31
32def getOutput(o):
33 import fcntl
34 fl = fcntl.fcntl(o, fcntl.F_GETFL)
35 fcntl.fcntl(o, fcntl.F_SETFL, fl | os.O_NONBLOCK)
36 try:
37 return os.read(o.fileno(), 1000000).decode("utf-8")
38 except BlockingIOError:
39 return ""
40
32class QemuRunner: 41class QemuRunner:
33 42
34 def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, boottime, dump_dir, use_kvm, logger, use_slirp=False, 43 def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, boottime, dump_dir, use_kvm, logger, use_slirp=False,
@@ -55,6 +64,7 @@ class QemuRunner:
55 self.boottime = boottime 64 self.boottime = boottime
56 self.logged = False 65 self.logged = False
57 self.thread = None 66 self.thread = None
67 self.threadsock = None
58 self.use_kvm = use_kvm 68 self.use_kvm = use_kvm
59 self.use_ovmf = use_ovmf 69 self.use_ovmf = use_ovmf
60 self.use_slirp = use_slirp 70 self.use_slirp = use_slirp
@@ -119,21 +129,11 @@ class QemuRunner:
119 f.write(msg) 129 f.write(msg)
120 self.msg += self.decode_qemulog(msg) 130 self.msg += self.decode_qemulog(msg)
121 131
122 def getOutput(self, o):
123 import fcntl
124 fl = fcntl.fcntl(o, fcntl.F_GETFL)
125 fcntl.fcntl(o, fcntl.F_SETFL, fl | os.O_NONBLOCK)
126 try:
127 return os.read(o.fileno(), 1000000).decode("utf-8")
128 except BlockingIOError:
129 return ""
130
131
132 def handleSIGCHLD(self, signum, frame): 132 def handleSIGCHLD(self, signum, frame):
133 if self.runqemu and self.runqemu.poll(): 133 if self.runqemu and self.runqemu.poll():
134 if self.runqemu.returncode: 134 if self.runqemu.returncode:
135 self.logger.error('runqemu exited with code %d' % self.runqemu.returncode) 135 self.logger.error('runqemu exited with code %d' % self.runqemu.returncode)
136 self.logger.error('Output from runqemu:\n%s' % self.getOutput(self.runqemu.stdout)) 136 self.logger.error('Output from runqemu:\n%s' % getOutput(self.runqemu.stdout))
137 self.stop() 137 self.stop()
138 138
139 def start(self, qemuparams = None, get_ip = True, extra_bootparams = None, runqemuparams='', launch_cmd=None, discard_writes=True): 139 def start(self, qemuparams = None, get_ip = True, extra_bootparams = None, runqemuparams='', launch_cmd=None, discard_writes=True):
@@ -282,7 +282,7 @@ class QemuRunner:
282 if self.runqemu.returncode: 282 if self.runqemu.returncode:
283 # No point waiting any longer 283 # No point waiting any longer
284 self.logger.warning('runqemu exited with code %d' % self.runqemu.returncode) 284 self.logger.warning('runqemu exited with code %d' % self.runqemu.returncode)
285 self.logger.warning("Output from runqemu:\n%s" % self.getOutput(output)) 285 self.logger.warning("Output from runqemu:\n%s" % getOutput(output))
286 self.stop() 286 self.stop()
287 return False 287 return False
288 time.sleep(0.5) 288 time.sleep(0.5)
@@ -309,7 +309,7 @@ class QemuRunner:
309 ps = subprocess.Popen(['ps', 'axww', '-o', 'pid,ppid,pri,ni,command '], stdout=subprocess.PIPE).communicate()[0] 309 ps = subprocess.Popen(['ps', 'axww', '-o', 'pid,ppid,pri,ni,command '], stdout=subprocess.PIPE).communicate()[0]
310 processes = ps.decode("utf-8") 310 processes = ps.decode("utf-8")
311 self.logger.debug("Running processes:\n%s" % processes) 311 self.logger.debug("Running processes:\n%s" % processes)
312 op = self.getOutput(output) 312 op = getOutput(output)
313 self.stop() 313 self.stop()
314 if op: 314 if op:
315 self.logger.error("Output from runqemu:\n%s" % op) 315 self.logger.error("Output from runqemu:\n%s" % op)
@@ -387,7 +387,7 @@ class QemuRunner:
387 time.time() - connect_time)) 387 time.time() - connect_time))
388 388
389 # We are alive: qemu is running 389 # We are alive: qemu is running
390 out = self.getOutput(output) 390 out = getOutput(output)
391 netconf = False # network configuration is not required by default 391 netconf = False # network configuration is not required by default
392 self.logger.debug("qemu started in %.2f seconds - qemu procces pid is %s (%s)" % 392 self.logger.debug("qemu started in %.2f seconds - qemu procces pid is %s (%s)" %
393 (time.time() - (endtime - self.runqemutime), 393 (time.time() - (endtime - self.runqemutime),
@@ -430,9 +430,10 @@ class QemuRunner:
430 self.logger.debug("Target IP: %s" % self.ip) 430 self.logger.debug("Target IP: %s" % self.ip)
431 self.logger.debug("Server IP: %s" % self.server_ip) 431 self.logger.debug("Server IP: %s" % self.server_ip)
432 432
433 self.thread = LoggingThread(self.log, self.threadsock, self.logger, self.runqemu.stdout)
434 self.thread.start()
435
433 if self.serial_ports >= 2: 436 if self.serial_ports >= 2:
434 self.thread = LoggingThread(self.log, self.threadsock, self.logger)
435 self.thread.start()
436 if not self.thread.connection_established.wait(self.boottime): 437 if not self.thread.connection_established.wait(self.boottime):
437 self.logger.error("Didn't receive a console connection from qemu. " 438 self.logger.error("Didn't receive a console connection from qemu. "
438 "Here is the qemu command line used:\n%s\nand " 439 "Here is the qemu command line used:\n%s\nand "
@@ -444,7 +445,7 @@ class QemuRunner:
444 self.logger.debug("Waiting at most %d seconds for login banner (%s)" % 445 self.logger.debug("Waiting at most %d seconds for login banner (%s)" %
445 (self.boottime, time.strftime("%D %H:%M:%S"))) 446 (self.boottime, time.strftime("%D %H:%M:%S")))
446 endtime = time.time() + self.boottime 447 endtime = time.time() + self.boottime
447 filelist = [self.server_socket, self.runqemu.stdout] 448 filelist = [self.server_socket]
448 reachedlogin = False 449 reachedlogin = False
449 stopread = False 450 stopread = False
450 qemusock = None 451 qemusock = None
@@ -564,7 +565,7 @@ class QemuRunner:
564 self.logger.debug("Sending SIGKILL to runqemu") 565 self.logger.debug("Sending SIGKILL to runqemu")
565 os.killpg(os.getpgid(self.runqemu.pid), signal.SIGKILL) 566 os.killpg(os.getpgid(self.runqemu.pid), signal.SIGKILL)
566 if not self.runqemu.stdout.closed: 567 if not self.runqemu.stdout.closed:
567 self.logger.info("Output from runqemu:\n%s" % self.getOutput(self.runqemu.stdout)) 568 self.logger.info("Output from runqemu:\n%s" % getOutput(self.runqemu.stdout))
568 self.runqemu.stdin.close() 569 self.runqemu.stdin.close()
569 self.runqemu.stdout.close() 570 self.runqemu.stdout.close()
570 self.runqemu_exited = True 571 self.runqemu_exited = True
@@ -700,9 +701,11 @@ class QemuRunner:
700# event loop. The mechanism for stopping the thread is a simple pipe which 701# event loop. The mechanism for stopping the thread is a simple pipe which
701# will wake up the poll and allow for tearing everything down. 702# will wake up the poll and allow for tearing everything down.
702class LoggingThread(threading.Thread): 703class LoggingThread(threading.Thread):
703 def __init__(self, logfunc, sock, logger): 704 def __init__(self, logfunc, sock, logger, qemuoutput):
704 self.connection_established = threading.Event() 705 self.connection_established = threading.Event()
706
705 self.serversock = sock 707 self.serversock = sock
708 self.qemuoutput = qemuoutput
706 self.logfunc = logfunc 709 self.logfunc = logfunc
707 self.logger = logger 710 self.logger = logger
708 self.readsock = None 711 self.readsock = None
@@ -732,7 +735,8 @@ class LoggingThread(threading.Thread):
732 735
733 def teardown(self): 736 def teardown(self):
734 self.logger.debug("Tearing down logging thread") 737 self.logger.debug("Tearing down logging thread")
735 self.close_socket(self.serversock) 738 if self.serversock:
739 self.close_socket(self.serversock)
736 740
737 if self.readsock is not None: 741 if self.readsock is not None:
738 self.close_socket(self.readsock) 742 self.close_socket(self.readsock)
@@ -747,7 +751,9 @@ class LoggingThread(threading.Thread):
747 def eventloop(self): 751 def eventloop(self):
748 poll = select.poll() 752 poll = select.poll()
749 event_read_mask = self.errorevents | self.readevents 753 event_read_mask = self.errorevents | self.readevents
750 poll.register(self.serversock.fileno()) 754 if self.serversock:
755 poll.register(self.serversock.fileno())
756 poll.register(self.qemuoutput.fileno())
751 poll.register(self.readpipe, event_read_mask) 757 poll.register(self.readpipe, event_read_mask)
752 758
753 breakout = False 759 breakout = False
@@ -767,7 +773,7 @@ class LoggingThread(threading.Thread):
767 break 773 break
768 774
769 # A connection request was received 775 # A connection request was received
770 elif self.serversock.fileno() == event[0]: 776 elif self.serversock and self.serversock.fileno() == event[0]:
771 self.logger.debug("Connection request received") 777 self.logger.debug("Connection request received")
772 self.readsock, _ = self.serversock.accept() 778 self.readsock, _ = self.serversock.accept()
773 self.readsock.setblocking(0) 779 self.readsock.setblocking(0)
@@ -781,6 +787,10 @@ class LoggingThread(threading.Thread):
781 elif self.readsock.fileno() == event[0]: 787 elif self.readsock.fileno() == event[0]:
782 data = self.recv(1024) 788 data = self.recv(1024)
783 self.logfunc(data) 789 self.logfunc(data)
790 elif self.qemuoutput.fileno() == event[0]:
791 data = self.qemuoutput.read()
792 self.logger.debug("Data received on qemu stdout %s" % data)
793 self.logfunc(data, ".stdout")
784 794
785 # Since the socket is non-blocking make sure to honor EAGAIN 795 # Since the socket is non-blocking make sure to honor EAGAIN
786 # and EWOULDBLOCK. 796 # and EWOULDBLOCK.