xref: /OK3568_Linux_fs/yocto/poky/bitbake/lib/bb/ui/uievent.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#
2*4882a593Smuzhiyun# Copyright (C) 2006 - 2007  Michael 'Mickey' Lauer
3*4882a593Smuzhiyun# Copyright (C) 2006 - 2007  Richard Purdie
4*4882a593Smuzhiyun#
5*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only
6*4882a593Smuzhiyun#
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun"""
9*4882a593SmuzhiyunUse this class to fork off a thread to recieve event callbacks from the bitbake
10*4882a593Smuzhiyunserver and queue them for the UI to process. This process must be used to avoid
11*4882a593Smuzhiyunclient/server deadlocks.
12*4882a593Smuzhiyun"""
13*4882a593Smuzhiyun
14*4882a593Smuzhiyunimport collections, logging, pickle, socket, threading
15*4882a593Smuzhiyunfrom xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
16*4882a593Smuzhiyun
17*4882a593Smuzhiyunimport bb
18*4882a593Smuzhiyun
19*4882a593Smuzhiyunlogger = logging.getLogger(__name__)
20*4882a593Smuzhiyun
21*4882a593Smuzhiyunclass BBUIEventQueue:
22*4882a593Smuzhiyun    def __init__(self, BBServer, clientinfo=("localhost, 0")):
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun        self.eventQueue = []
25*4882a593Smuzhiyun        self.eventQueueLock = threading.Lock()
26*4882a593Smuzhiyun        self.eventQueueNotify = threading.Event()
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun        self.BBServer = BBServer
29*4882a593Smuzhiyun        self.clientinfo = clientinfo
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun        server = UIXMLRPCServer(self.clientinfo)
32*4882a593Smuzhiyun        self.host, self.port = server.socket.getsockname()
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun        server.register_function( self.system_quit, "event.quit" )
35*4882a593Smuzhiyun        server.register_function( self.send_event, "event.sendpickle" )
36*4882a593Smuzhiyun        server.socket.settimeout(1)
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun        self.EventHandle = None
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun        # the event handler registration may fail here due to cooker being in invalid state
41*4882a593Smuzhiyun        # this is a transient situation, and we should retry a couple of times before
42*4882a593Smuzhiyun        # giving up
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun        for count_tries in range(5):
45*4882a593Smuzhiyun            ret = self.BBServer.registerEventHandler(self.host, self.port)
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun            if isinstance(ret, collections.abc.Iterable):
48*4882a593Smuzhiyun                self.EventHandle, error = ret
49*4882a593Smuzhiyun            else:
50*4882a593Smuzhiyun                self.EventHandle = ret
51*4882a593Smuzhiyun                error = ""
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun            if self.EventHandle is not None:
54*4882a593Smuzhiyun                break
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun            errmsg = "Could not register UI event handler. Error: %s, host %s, "\
57*4882a593Smuzhiyun                     "port %d" % (error, self.host, self.port)
58*4882a593Smuzhiyun            bb.warn("%s, retry" % errmsg)
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun            import time
61*4882a593Smuzhiyun            time.sleep(1)
62*4882a593Smuzhiyun        else:
63*4882a593Smuzhiyun            raise Exception(errmsg)
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun        self.server = server
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun        self.t = threading.Thread()
68*4882a593Smuzhiyun        self.t.setDaemon(True)
69*4882a593Smuzhiyun        self.t.run = self.startCallbackHandler
70*4882a593Smuzhiyun        self.t.start()
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun    def getEvent(self):
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun        self.eventQueueLock.acquire()
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun        if not self.eventQueue:
77*4882a593Smuzhiyun            self.eventQueueLock.release()
78*4882a593Smuzhiyun            return None
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun        item = self.eventQueue.pop(0)
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun        if not self.eventQueue:
83*4882a593Smuzhiyun            self.eventQueueNotify.clear()
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun        self.eventQueueLock.release()
86*4882a593Smuzhiyun        return item
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun    def waitEvent(self, delay):
89*4882a593Smuzhiyun        self.eventQueueNotify.wait(delay)
90*4882a593Smuzhiyun        return self.getEvent()
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun    def queue_event(self, event):
93*4882a593Smuzhiyun        self.eventQueueLock.acquire()
94*4882a593Smuzhiyun        self.eventQueue.append(event)
95*4882a593Smuzhiyun        self.eventQueueNotify.set()
96*4882a593Smuzhiyun        self.eventQueueLock.release()
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun    def send_event(self, event):
99*4882a593Smuzhiyun        self.queue_event(pickle.loads(event))
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun    def startCallbackHandler(self):
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun        self.server.timeout = 1
104*4882a593Smuzhiyun        bb.utils.set_process_name("UIEventQueue")
105*4882a593Smuzhiyun        while not self.server.quit:
106*4882a593Smuzhiyun            try:
107*4882a593Smuzhiyun                self.server.handle_request()
108*4882a593Smuzhiyun            except Exception as e:
109*4882a593Smuzhiyun                import traceback
110*4882a593Smuzhiyun                logger.error("BBUIEventQueue.startCallbackHandler: Exception while trying to handle request: %s\n%s" % (e, traceback.format_exc()))
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun        self.server.server_close()
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun    def system_quit( self ):
115*4882a593Smuzhiyun        """
116*4882a593Smuzhiyun        Shut down the callback thread
117*4882a593Smuzhiyun        """
118*4882a593Smuzhiyun        try:
119*4882a593Smuzhiyun            self.BBServer.unregisterEventHandler(self.EventHandle)
120*4882a593Smuzhiyun        except:
121*4882a593Smuzhiyun            pass
122*4882a593Smuzhiyun        self.server.quit = True
123*4882a593Smuzhiyun
124*4882a593Smuzhiyunclass UIXMLRPCServer (SimpleXMLRPCServer):
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun    def __init__( self, interface ):
127*4882a593Smuzhiyun        self.quit = False
128*4882a593Smuzhiyun        SimpleXMLRPCServer.__init__( self,
129*4882a593Smuzhiyun                                    interface,
130*4882a593Smuzhiyun                                    requestHandler=SimpleXMLRPCRequestHandler,
131*4882a593Smuzhiyun                                    logRequests=False, allow_none=True, use_builtin_types=True)
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun    def get_request(self):
134*4882a593Smuzhiyun        while not self.quit:
135*4882a593Smuzhiyun            try:
136*4882a593Smuzhiyun                sock, addr = self.socket.accept()
137*4882a593Smuzhiyun                sock.settimeout(1)
138*4882a593Smuzhiyun                return (sock, addr)
139*4882a593Smuzhiyun            except socket.timeout:
140*4882a593Smuzhiyun                pass
141*4882a593Smuzhiyun        return (None, None)
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun    def close_request(self, request):
144*4882a593Smuzhiyun        if request is None:
145*4882a593Smuzhiyun            return
146*4882a593Smuzhiyun        SimpleXMLRPCServer.close_request(self, request)
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun    def process_request(self, request, client_address):
149*4882a593Smuzhiyun        if request is None:
150*4882a593Smuzhiyun            return
151*4882a593Smuzhiyun        SimpleXMLRPCServer.process_request(self, request, client_address)
152*4882a593Smuzhiyun
153