blob: fedb05064dff45926e260394896eb7af48735b5c [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
2# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
3# Copyright (C) 2006 - 2007 Richard Purdie
4#
Brad Bishopc342db32019-05-15 21:57:59 -04005# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -05006#
Patrick Williamsc124f4f2015-09-15 14:41:29 -05007
8"""
9Use this class to fork off a thread to recieve event callbacks from the bitbake
10server and queue them for the UI to process. This process must be used to avoid
11client/server deadlocks.
12"""
13
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050014import socket, threading, pickle, collections
Patrick Williamsc0f7c042017-02-23 20:41:17 -060015from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
Patrick Williamsc124f4f2015-09-15 14:41:29 -050016
17class BBUIEventQueue:
18 def __init__(self, BBServer, clientinfo=("localhost, 0")):
19
20 self.eventQueue = []
21 self.eventQueueLock = threading.Lock()
22 self.eventQueueNotify = threading.Event()
23
24 self.BBServer = BBServer
25 self.clientinfo = clientinfo
26
27 server = UIXMLRPCServer(self.clientinfo)
28 self.host, self.port = server.socket.getsockname()
29
30 server.register_function( self.system_quit, "event.quit" )
31 server.register_function( self.send_event, "event.sendpickle" )
32 server.socket.settimeout(1)
33
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050034 self.EventHandle = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -050035
36 # the event handler registration may fail here due to cooker being in invalid state
37 # this is a transient situation, and we should retry a couple of times before
38 # giving up
39
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050040 for count_tries in range(5):
41 ret = self.BBServer.registerEventHandler(self.host, self.port)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050042
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050043 if isinstance(ret, collections.Iterable):
44 self.EventHandle, error = ret
45 else:
46 self.EventHandle = ret
47 error = ""
48
49 if self.EventHandle != None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050050 break
51
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050052 errmsg = "Could not register UI event handler. Error: %s, host %s, "\
53 "port %d" % (error, self.host, self.port)
54 bb.warn("%s, retry" % errmsg)
55
Patrick Williamsc124f4f2015-09-15 14:41:29 -050056 import time
57 time.sleep(1)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050058 else:
59 raise Exception(errmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050060
61 self.server = server
62
63 self.t = threading.Thread()
64 self.t.setDaemon(True)
65 self.t.run = self.startCallbackHandler
66 self.t.start()
67
68 def getEvent(self):
69
70 self.eventQueueLock.acquire()
71
72 if len(self.eventQueue) == 0:
73 self.eventQueueLock.release()
74 return None
75
76 item = self.eventQueue.pop(0)
77
78 if len(self.eventQueue) == 0:
79 self.eventQueueNotify.clear()
80
81 self.eventQueueLock.release()
82 return item
83
84 def waitEvent(self, delay):
85 self.eventQueueNotify.wait(delay)
86 return self.getEvent()
87
88 def queue_event(self, event):
89 self.eventQueueLock.acquire()
90 self.eventQueue.append(event)
91 self.eventQueueNotify.set()
92 self.eventQueueLock.release()
93
94 def send_event(self, event):
95 self.queue_event(pickle.loads(event))
96
97 def startCallbackHandler(self):
98
99 self.server.timeout = 1
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500100 bb.utils.set_process_name("UIEventQueue")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500101 while not self.server.quit:
102 try:
103 self.server.handle_request()
104 except Exception as e:
105 import traceback
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600106 logger.error("BBUIEventQueue.startCallbackHandler: Exception while trying to handle request: %s\n%s" % (e, traceback.format_exc()))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500107
108 self.server.server_close()
109
110 def system_quit( self ):
111 """
112 Shut down the callback thread
113 """
114 try:
115 self.BBServer.unregisterEventHandler(self.EventHandle)
116 except:
117 pass
118 self.server.quit = True
119
120class UIXMLRPCServer (SimpleXMLRPCServer):
121
122 def __init__( self, interface ):
123 self.quit = False
124 SimpleXMLRPCServer.__init__( self,
125 interface,
126 requestHandler=SimpleXMLRPCRequestHandler,
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600127 logRequests=False, allow_none=True, use_builtin_types=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500128
129 def get_request(self):
130 while not self.quit:
131 try:
132 sock, addr = self.socket.accept()
133 sock.settimeout(1)
134 return (sock, addr)
135 except socket.timeout:
136 pass
137 return (None, None)
138
139 def close_request(self, request):
140 if request is None:
141 return
142 SimpleXMLRPCServer.close_request(self, request)
143
144 def process_request(self, request, client_address):
145 if request is None:
146 return
147 SimpleXMLRPCServer.process_request(self, request, client_address)
148