uievent.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #
  2. # Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
  3. # Copyright (C) 2006 - 2007 Richard Purdie
  4. #
  5. # SPDX-License-Identifier: GPL-2.0-only
  6. #
  7. """
  8. Use this class to fork off a thread to recieve event callbacks from the bitbake
  9. server and queue them for the UI to process. This process must be used to avoid
  10. client/server deadlocks.
  11. """
  12. import collections, logging, pickle, socket, threading
  13. from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
  14. import bb
  15. logger = logging.getLogger(__name__)
  16. class BBUIEventQueue:
  17. def __init__(self, BBServer, clientinfo=("localhost, 0")):
  18. self.eventQueue = []
  19. self.eventQueueLock = threading.Lock()
  20. self.eventQueueNotify = threading.Event()
  21. self.BBServer = BBServer
  22. self.clientinfo = clientinfo
  23. server = UIXMLRPCServer(self.clientinfo)
  24. self.host, self.port = server.socket.getsockname()
  25. server.register_function( self.system_quit, "event.quit" )
  26. server.register_function( self.send_event, "event.sendpickle" )
  27. server.socket.settimeout(1)
  28. self.EventHandle = None
  29. # the event handler registration may fail here due to cooker being in invalid state
  30. # this is a transient situation, and we should retry a couple of times before
  31. # giving up
  32. for count_tries in range(5):
  33. ret = self.BBServer.registerEventHandler(self.host, self.port)
  34. if isinstance(ret, collections.Iterable):
  35. self.EventHandle, error = ret
  36. else:
  37. self.EventHandle = ret
  38. error = ""
  39. if self.EventHandle is not None:
  40. break
  41. errmsg = "Could not register UI event handler. Error: %s, host %s, "\
  42. "port %d" % (error, self.host, self.port)
  43. bb.warn("%s, retry" % errmsg)
  44. import time
  45. time.sleep(1)
  46. else:
  47. raise Exception(errmsg)
  48. self.server = server
  49. self.t = threading.Thread()
  50. self.t.setDaemon(True)
  51. self.t.run = self.startCallbackHandler
  52. self.t.start()
  53. def getEvent(self):
  54. self.eventQueueLock.acquire()
  55. if len(self.eventQueue) == 0:
  56. self.eventQueueLock.release()
  57. return None
  58. item = self.eventQueue.pop(0)
  59. if len(self.eventQueue) == 0:
  60. self.eventQueueNotify.clear()
  61. self.eventQueueLock.release()
  62. return item
  63. def waitEvent(self, delay):
  64. self.eventQueueNotify.wait(delay)
  65. return self.getEvent()
  66. def queue_event(self, event):
  67. self.eventQueueLock.acquire()
  68. self.eventQueue.append(event)
  69. self.eventQueueNotify.set()
  70. self.eventQueueLock.release()
  71. def send_event(self, event):
  72. self.queue_event(pickle.loads(event))
  73. def startCallbackHandler(self):
  74. self.server.timeout = 1
  75. bb.utils.set_process_name("UIEventQueue")
  76. while not self.server.quit:
  77. try:
  78. self.server.handle_request()
  79. except Exception as e:
  80. import traceback
  81. logger.error("BBUIEventQueue.startCallbackHandler: Exception while trying to handle request: %s\n%s" % (e, traceback.format_exc()))
  82. self.server.server_close()
  83. def system_quit( self ):
  84. """
  85. Shut down the callback thread
  86. """
  87. try:
  88. self.BBServer.unregisterEventHandler(self.EventHandle)
  89. except:
  90. pass
  91. self.server.quit = True
  92. class UIXMLRPCServer (SimpleXMLRPCServer):
  93. def __init__( self, interface ):
  94. self.quit = False
  95. SimpleXMLRPCServer.__init__( self,
  96. interface,
  97. requestHandler=SimpleXMLRPCRequestHandler,
  98. logRequests=False, allow_none=True, use_builtin_types=True)
  99. def get_request(self):
  100. while not self.quit:
  101. try:
  102. sock, addr = self.socket.accept()
  103. sock.settimeout(1)
  104. return (sock, addr)
  105. except socket.timeout:
  106. pass
  107. return (None, None)
  108. def close_request(self, request):
  109. if request is None:
  110. return
  111. SimpleXMLRPCServer.close_request(self, request)
  112. def process_request(self, request, client_address):
  113. if request is None:
  114. return
  115. SimpleXMLRPCServer.process_request(self, request, client_address)