blob: 9542b911ca0984ccdb6aac550e6ef610b538cf75 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3#
4# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
5# Copyright (C) 2006 - 2007 Richard Purdie
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 2 as
9# published by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program; if not, write to the Free Software Foundation, Inc.,
18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
21"""
22Use this class to fork off a thread to recieve event callbacks from the bitbake
23server and queue them for the UI to process. This process must be used to avoid
24client/server deadlocks.
25"""
26
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050027import socket, threading, pickle, collections
Patrick Williamsc0f7c042017-02-23 20:41:17 -060028from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
Patrick Williamsc124f4f2015-09-15 14:41:29 -050029
30class BBUIEventQueue:
31 def __init__(self, BBServer, clientinfo=("localhost, 0")):
32
33 self.eventQueue = []
34 self.eventQueueLock = threading.Lock()
35 self.eventQueueNotify = threading.Event()
36
37 self.BBServer = BBServer
38 self.clientinfo = clientinfo
39
40 server = UIXMLRPCServer(self.clientinfo)
41 self.host, self.port = server.socket.getsockname()
42
43 server.register_function( self.system_quit, "event.quit" )
44 server.register_function( self.send_event, "event.sendpickle" )
45 server.socket.settimeout(1)
46
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050047 self.EventHandle = None
Patrick Williamsc124f4f2015-09-15 14:41:29 -050048
49 # the event handler registration may fail here due to cooker being in invalid state
50 # this is a transient situation, and we should retry a couple of times before
51 # giving up
52
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050053 for count_tries in range(5):
54 ret = self.BBServer.registerEventHandler(self.host, self.port)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050055
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050056 if isinstance(ret, collections.Iterable):
57 self.EventHandle, error = ret
58 else:
59 self.EventHandle = ret
60 error = ""
61
62 if self.EventHandle != None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050063 break
64
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050065 errmsg = "Could not register UI event handler. Error: %s, host %s, "\
66 "port %d" % (error, self.host, self.port)
67 bb.warn("%s, retry" % errmsg)
68
Patrick Williamsc124f4f2015-09-15 14:41:29 -050069 import time
70 time.sleep(1)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050071 else:
72 raise Exception(errmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050073
74 self.server = server
75
76 self.t = threading.Thread()
77 self.t.setDaemon(True)
78 self.t.run = self.startCallbackHandler
79 self.t.start()
80
81 def getEvent(self):
82
83 self.eventQueueLock.acquire()
84
85 if len(self.eventQueue) == 0:
86 self.eventQueueLock.release()
87 return None
88
89 item = self.eventQueue.pop(0)
90
91 if len(self.eventQueue) == 0:
92 self.eventQueueNotify.clear()
93
94 self.eventQueueLock.release()
95 return item
96
97 def waitEvent(self, delay):
98 self.eventQueueNotify.wait(delay)
99 return self.getEvent()
100
101 def queue_event(self, event):
102 self.eventQueueLock.acquire()
103 self.eventQueue.append(event)
104 self.eventQueueNotify.set()
105 self.eventQueueLock.release()
106
107 def send_event(self, event):
108 self.queue_event(pickle.loads(event))
109
110 def startCallbackHandler(self):
111
112 self.server.timeout = 1
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500113 bb.utils.set_process_name("UIEventQueue")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500114 while not self.server.quit:
115 try:
116 self.server.handle_request()
117 except Exception as e:
118 import traceback
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600119 logger.error("BBUIEventQueue.startCallbackHandler: Exception while trying to handle request: %s\n%s" % (e, traceback.format_exc()))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500120
121 self.server.server_close()
122
123 def system_quit( self ):
124 """
125 Shut down the callback thread
126 """
127 try:
128 self.BBServer.unregisterEventHandler(self.EventHandle)
129 except:
130 pass
131 self.server.quit = True
132
133class UIXMLRPCServer (SimpleXMLRPCServer):
134
135 def __init__( self, interface ):
136 self.quit = False
137 SimpleXMLRPCServer.__init__( self,
138 interface,
139 requestHandler=SimpleXMLRPCRequestHandler,
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600140 logRequests=False, allow_none=True, use_builtin_types=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500141
142 def get_request(self):
143 while not self.quit:
144 try:
145 sock, addr = self.socket.accept()
146 sock.settimeout(1)
147 return (sock, addr)
148 except socket.timeout:
149 pass
150 return (None, None)
151
152 def close_request(self, request):
153 if request is None:
154 return
155 SimpleXMLRPCServer.close_request(self, request)
156
157 def process_request(self, request, client_address):
158 if request is None:
159 return
160 SimpleXMLRPCServer.process_request(self, request, client_address)
161