blob: d595f172ac0e701c98fa1755fd8a068900a96ecf [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
Andrew Geisslerc9f78652020-09-18 14:11:35 -050014import collections, logging, pickle, socket, threading
Patrick Williamsc0f7c042017-02-23 20:41:17 -060015from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
Patrick Williamsc124f4f2015-09-15 14:41:29 -050016
Andrew Geisslerc9f78652020-09-18 14:11:35 -050017import bb
18
19logger = logging.getLogger(__name__)
20
Patrick Williamsc124f4f2015-09-15 14:41:29 -050021class BBUIEventQueue:
22 def __init__(self, BBServer, clientinfo=("localhost, 0")):
23
24 self.eventQueue = []
25 self.eventQueueLock = threading.Lock()
26 self.eventQueueNotify = threading.Event()
27
28 self.BBServer = BBServer
29 self.clientinfo = clientinfo
30
31 server = UIXMLRPCServer(self.clientinfo)
32 self.host, self.port = server.socket.getsockname()
33
34 server.register_function( self.system_quit, "event.quit" )
35 server.register_function( self.send_event, "event.sendpickle" )
36 server.socket.settimeout(1)
37
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050038 self.EventHandle = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -050039
40 # the event handler registration may fail here due to cooker being in invalid state
41 # this is a transient situation, and we should retry a couple of times before
42 # giving up
43
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050044 for count_tries in range(5):
45 ret = self.BBServer.registerEventHandler(self.host, self.port)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046
Andrew Geissler9aee5002022-03-30 16:27:02 +000047 if isinstance(ret, collections.abc.Iterable):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050048 self.EventHandle, error = ret
49 else:
50 self.EventHandle = ret
51 error = ""
52
Andrew Geissler82c905d2020-04-13 13:39:40 -050053 if self.EventHandle is not None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050054 break
55
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050056 errmsg = "Could not register UI event handler. Error: %s, host %s, "\
57 "port %d" % (error, self.host, self.port)
58 bb.warn("%s, retry" % errmsg)
59
Patrick Williamsc124f4f2015-09-15 14:41:29 -050060 import time
61 time.sleep(1)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050062 else:
63 raise Exception(errmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050064
65 self.server = server
66
67 self.t = threading.Thread()
68 self.t.setDaemon(True)
69 self.t.run = self.startCallbackHandler
70 self.t.start()
71
72 def getEvent(self):
73
74 self.eventQueueLock.acquire()
75
Andrew Geissler595f6302022-01-24 19:11:47 +000076 if not self.eventQueue:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050077 self.eventQueueLock.release()
78 return None
79
80 item = self.eventQueue.pop(0)
81
Andrew Geissler595f6302022-01-24 19:11:47 +000082 if not self.eventQueue:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050083 self.eventQueueNotify.clear()
84
85 self.eventQueueLock.release()
86 return item
87
88 def waitEvent(self, delay):
89 self.eventQueueNotify.wait(delay)
90 return self.getEvent()
91
92 def queue_event(self, event):
93 self.eventQueueLock.acquire()
94 self.eventQueue.append(event)
95 self.eventQueueNotify.set()
96 self.eventQueueLock.release()
97
98 def send_event(self, event):
99 self.queue_event(pickle.loads(event))
100
101 def startCallbackHandler(self):
102
103 self.server.timeout = 1
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500104 bb.utils.set_process_name("UIEventQueue")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500105 while not self.server.quit:
106 try:
107 self.server.handle_request()
108 except Exception as e:
109 import traceback
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600110 logger.error("BBUIEventQueue.startCallbackHandler: Exception while trying to handle request: %s\n%s" % (e, traceback.format_exc()))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500111
112 self.server.server_close()
113
114 def system_quit( self ):
115 """
116 Shut down the callback thread
117 """
118 try:
119 self.BBServer.unregisterEventHandler(self.EventHandle)
120 except:
121 pass
122 self.server.quit = True
123
124class UIXMLRPCServer (SimpleXMLRPCServer):
125
126 def __init__( self, interface ):
127 self.quit = False
128 SimpleXMLRPCServer.__init__( self,
129 interface,
130 requestHandler=SimpleXMLRPCRequestHandler,
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600131 logRequests=False, allow_none=True, use_builtin_types=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132
133 def get_request(self):
134 while not self.quit:
135 try:
136 sock, addr = self.socket.accept()
137 sock.settimeout(1)
138 return (sock, addr)
139 except socket.timeout:
140 pass
141 return (None, None)
142
143 def close_request(self, request):
144 if request is None:
145 return
146 SimpleXMLRPCServer.close_request(self, request)
147
148 def process_request(self, request, client_address):
149 if request is None:
150 return
151 SimpleXMLRPCServer.process_request(self, request, client_address)
152