blob: adbe6989390977aa736242e466b4358374401a19 [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):
Andrew Geissler517393d2023-01-13 08:55:19 -060073 with bb.utils.lock_timeout(self.eventQueueLock):
74 if not self.eventQueue:
75 return None
76 item = self.eventQueue.pop(0)
77 if not self.eventQueue:
78 self.eventQueueNotify.clear()
79 return item
Patrick Williamsc124f4f2015-09-15 14:41:29 -050080
81 def waitEvent(self, delay):
82 self.eventQueueNotify.wait(delay)
83 return self.getEvent()
84
85 def queue_event(self, event):
Andrew Geissler517393d2023-01-13 08:55:19 -060086 with bb.utils.lock_timeout(self.eventQueueLock):
87 self.eventQueue.append(event)
88 self.eventQueueNotify.set()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050089
90 def send_event(self, event):
91 self.queue_event(pickle.loads(event))
92
93 def startCallbackHandler(self):
94
95 self.server.timeout = 1
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050096 bb.utils.set_process_name("UIEventQueue")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050097 while not self.server.quit:
98 try:
99 self.server.handle_request()
100 except Exception as e:
101 import traceback
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600102 logger.error("BBUIEventQueue.startCallbackHandler: Exception while trying to handle request: %s\n%s" % (e, traceback.format_exc()))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500103
104 self.server.server_close()
105
106 def system_quit( self ):
107 """
108 Shut down the callback thread
109 """
110 try:
111 self.BBServer.unregisterEventHandler(self.EventHandle)
112 except:
113 pass
114 self.server.quit = True
115
116class UIXMLRPCServer (SimpleXMLRPCServer):
117
118 def __init__( self, interface ):
119 self.quit = False
120 SimpleXMLRPCServer.__init__( self,
121 interface,
122 requestHandler=SimpleXMLRPCRequestHandler,
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600123 logRequests=False, allow_none=True, use_builtin_types=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500124
125 def get_request(self):
126 while not self.quit:
127 try:
128 sock, addr = self.socket.accept()
129 sock.settimeout(1)
130 return (sock, addr)
131 except socket.timeout:
132 pass
133 return (None, None)
134
135 def close_request(self, request):
136 if request is None:
137 return
138 SimpleXMLRPCServer.close_request(self, request)
139
140 def process_request(self, request, client_address):
141 if request is None:
142 return
143 SimpleXMLRPCServer.process_request(self, request, client_address)
144