123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- # ex:ts=4:sw=4:sts=4:et
- # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
- #
- # Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
- # Copyright (C) 2006 - 2007 Richard Purdie
- #
- # SPDX-License-Identifier: GPL-2.0-only
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License version 2 as
- # published by the Free Software Foundation.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License along
- # with this program; if not, write to the Free Software Foundation, Inc.,
- # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- """
- Use this class to fork off a thread to recieve event callbacks from the bitbake
- server and queue them for the UI to process. This process must be used to avoid
- client/server deadlocks.
- """
- import socket, threading, pickle, collections
- from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
- class BBUIEventQueue:
- def __init__(self, BBServer, clientinfo=("localhost, 0")):
- self.eventQueue = []
- self.eventQueueLock = threading.Lock()
- self.eventQueueNotify = threading.Event()
- self.BBServer = BBServer
- self.clientinfo = clientinfo
- server = UIXMLRPCServer(self.clientinfo)
- self.host, self.port = server.socket.getsockname()
- server.register_function( self.system_quit, "event.quit" )
- server.register_function( self.send_event, "event.sendpickle" )
- server.socket.settimeout(1)
- self.EventHandle = None
- # the event handler registration may fail here due to cooker being in invalid state
- # this is a transient situation, and we should retry a couple of times before
- # giving up
- for count_tries in range(5):
- ret = self.BBServer.registerEventHandler(self.host, self.port)
- if isinstance(ret, collections.Iterable):
- self.EventHandle, error = ret
- else:
- self.EventHandle = ret
- error = ""
- if self.EventHandle != None:
- break
- errmsg = "Could not register UI event handler. Error: %s, host %s, "\
- "port %d" % (error, self.host, self.port)
- bb.warn("%s, retry" % errmsg)
- import time
- time.sleep(1)
- else:
- raise Exception(errmsg)
- self.server = server
- self.t = threading.Thread()
- self.t.setDaemon(True)
- self.t.run = self.startCallbackHandler
- self.t.start()
- def getEvent(self):
- self.eventQueueLock.acquire()
- if len(self.eventQueue) == 0:
- self.eventQueueLock.release()
- return None
- item = self.eventQueue.pop(0)
- if len(self.eventQueue) == 0:
- self.eventQueueNotify.clear()
- self.eventQueueLock.release()
- return item
- def waitEvent(self, delay):
- self.eventQueueNotify.wait(delay)
- return self.getEvent()
- def queue_event(self, event):
- self.eventQueueLock.acquire()
- self.eventQueue.append(event)
- self.eventQueueNotify.set()
- self.eventQueueLock.release()
- def send_event(self, event):
- self.queue_event(pickle.loads(event))
- def startCallbackHandler(self):
- self.server.timeout = 1
- bb.utils.set_process_name("UIEventQueue")
- while not self.server.quit:
- try:
- self.server.handle_request()
- except Exception as e:
- import traceback
- logger.error("BBUIEventQueue.startCallbackHandler: Exception while trying to handle request: %s\n%s" % (e, traceback.format_exc()))
- self.server.server_close()
- def system_quit( self ):
- """
- Shut down the callback thread
- """
- try:
- self.BBServer.unregisterEventHandler(self.EventHandle)
- except:
- pass
- self.server.quit = True
- class UIXMLRPCServer (SimpleXMLRPCServer):
- def __init__( self, interface ):
- self.quit = False
- SimpleXMLRPCServer.__init__( self,
- interface,
- requestHandler=SimpleXMLRPCRequestHandler,
- logRequests=False, allow_none=True, use_builtin_types=True)
- def get_request(self):
- while not self.quit:
- try:
- sock, addr = self.socket.accept()
- sock.settimeout(1)
- return (sock, addr)
- except socket.timeout:
- pass
- return (None, None)
- def close_request(self, request):
- if request is None:
- return
- SimpleXMLRPCServer.close_request(self, request)
- def process_request(self, request, client_address):
- if request is None:
- return
- SimpleXMLRPCServer.process_request(self, request, client_address)
|