uievent.py 5.0 KB

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