aboutsummaryrefslogtreecommitdiffstats
path: root/lib/oeqa/utils/qemuzephyrrunner.py
blob: 441e0d641f9d478bbfff0de01ceeb6218640fb81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# Copyright (C) 2015-2016 Intel Corporation
#
# Released under the MIT license (see COPYING.MIT)

# This module provides a class for starting qemu images of poky tiny.
# It's used by testimage.bbclass.

import subprocess
import os
import time
import signal
import socket
import select
import bb
import tempfile
from oeqa.utils.qemurunner import QemuRunner

class QemuZephyrRunner(QemuRunner):

    def __init__(self, machine, rootfs, display, tmpdir, deploy_dir_image, logfile, kernel, boottime):
        QemuRunner.__init__(self, machine, rootfs, display, tmpdir,
                            deploy_dir_image, logfile, boottime, None,
                            None, True)

        # Popen object for runqemu
        self.socketfile = tempfile.NamedTemporaryFile()
        self.runqemu = None
        self.socketname = self.socketfile.name
        self.server_socket = None
        self.kernel = kernel

    def create_socket(self):
        bb.note("waiting at most %s seconds for qemu pid" % self.runqemutime)
        tries = self.runqemutime
        while tries > 0:
            time.sleep(1)
            try:
                self.server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                self.server_socket.connect(self.socketname)
                bb.note("Created listening socket for qemu serial console.")
                break

            except socket.error:
                self.server_socket.close()
                tries -= 1

        if tries == 0:
            bb.error("Failed to create listening socket %s: " % (self.socketname))
            return False
        return True

    def start(self, qemuparams = None, get_ip = True, extra_bootparams = None):

        if not os.path.exists(self.tmpdir):
            bb.error("Invalid TMPDIR path %s" % self.tmpdir)
            return False
        else:
            os.environ["OE_TMPDIR"] = self.tmpdir
        if not os.path.exists(self.deploy_dir_image):
            bb.error("Invalid DEPLOY_DIR_IMAGE path %s" % self.deploy_dir_image)
            return False
        else:
            os.environ["DEPLOY_DIR_IMAGE"] = self.deploy_dir_image

        if not os.path.exists(self.kernel):
            bb.error("Invalid kernel path: %s" % self.deploy_dir_image)
            return False

        self.qemuparams = '-nographic -serial unix:%s,server' % (self.socketname)
        qemu_binary = ""
        if 'arm' in self.machine or 'cortex' in self.machine:
            qemu_binary = 'qemu-system-arm'
            qemu_machine_args = '-machine lm3s6965evb'
        elif 'x86' in self.machine:
            qemu_binary = 'qemu-system-i386'
            qemu_machine_args = '-machine type=pc-0.14'

        self.origchldhandler = signal.getsignal(signal.SIGCHLD)
        signal.signal(signal.SIGCHLD, self.handleSIGCHLD)

        launch_cmd = '%s -kernel %s %s %s' % (qemu_binary, self.kernel, self.qemuparams, qemu_machine_args)
        bb.note(launch_cmd)
        self.runqemu = subprocess.Popen(launch_cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,preexec_fn=os.setpgrp)

        #
        # We need the preexec_fn above so that all runqemu processes can easily be killed
        # (by killing their process group). This presents a problem if this controlling
        # process itself is killed however since those processes don't notice the death
        # of the parent and merrily continue on.
        #
        # Rather than hack runqemu to deal with this, we add something here instead.
        # Basically we fork off another process which holds an open pipe to the parent
        # and also is setpgrp. If/when the pipe sees EOF from the parent dieing, it kills
        # the process group. This is like pctrl's PDEATHSIG but for a process group
        # rather than a single process.
        #
        r, w = os.pipe()
        self.monitorpid = os.fork()
        if self.monitorpid:
            os.close(r)
            self.monitorpipe = os.fdopen(w, "w")
        else:
            # child process
            os.setpgrp()
            os.close(w)
            r = os.fdopen(r)
            x = r.read()
            os.killpg(os.getpgid(self.runqemu.pid), signal.SIGTERM)
            sys.exit(0)

        bb.note("qemu started, pid is %s" % self.runqemu.pid)
        return self.create_socket()

    def wait_for_serial(self, func_timeout, data_timeout):
        stopread = False
        check_endtime = False
        self.server_socket.setblocking(0)
        endtime = time.time() + func_timeout

        while time.time() < endtime:
            sread, _, _ = select.select([self.server_socket],[],[],data_timeout)
            if not sread:
                break
            answer = self.server_socket.recv(1024)
            if answer:
                self.log(answer)
            else:
                break

        return self.logfile