serialhdl: Use reactor mutex in send_with_response()

Reduce the delay in send_with_response() by introducing a reactor
mutex to wake the main thread when the response is obtained.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2019-06-09 19:12:24 -04:00
parent 30d2ae8f9f
commit 97840f9851
1 changed files with 20 additions and 12 deletions

View File

@ -44,10 +44,10 @@ class SerialReader:
params['#sent_time'] = response.sent_time params['#sent_time'] = response.sent_time
params['#receive_time'] = response.receive_time params['#receive_time'] = response.receive_time
hdl = (params['#name'], params.get('oid')) hdl = (params['#name'], params.get('oid'))
with self.lock:
hdl = self.handlers.get(hdl, self.handle_default)
try: try:
hdl(params) with self.lock:
hdl = self.handlers.get(hdl, self.handle_default)
hdl(params)
except: except:
logging.exception("Exception in serial callback") logging.exception("Exception in serial callback")
def connect(self): def connect(self):
@ -197,29 +197,37 @@ class SerialRetryCommand:
self.name = name self.name = name
self.oid = oid self.oid = oid
self.response = None self.response = None
reactor = self.serial.reactor
self.mutex = reactor.mutex(is_locked=True)
self.min_query_time = self.serial.reactor.monotonic() self.min_query_time = self.serial.reactor.monotonic()
self.serial.register_callback(self.handle_callback, self.name, self.oid) self.serial.register_callback(self.handle_callback, self.name, self.oid)
self.send_timer = self.serial.reactor.register_timer( retry_time = self.send_event(self.min_query_time)
self.send_event, self.serial.reactor.NOW) self.send_timer = reactor.register_timer(self.send_event, retry_time)
def unregister(self): def unregister(self):
self.serial.unregister_callback(self.name, self.oid) self.serial.unregister_callback(self.name, self.oid)
self.serial.reactor.unregister_timer(self.send_timer) self.serial.reactor.unregister_timer(self.send_timer)
def send_event(self, eventtime): def send_event(self, eventtime):
if self.response is not None: if self.response is not None:
return self.serial.reactor.NEVER return self.serial.reactor.NEVER
if eventtime > self.min_query_time + self.TIMEOUT_TIME:
self.unregister()
if self.response is None:
self.mutex.unlock()
return self.serial.reactor.NEVER
self.serial.raw_send(self.cmd, 0, 0, self.serial.default_cmd_queue) self.serial.raw_send(self.cmd, 0, 0, self.serial.default_cmd_queue)
return eventtime + self.RETRY_TIME return eventtime + self.RETRY_TIME
def handle_callback(self, params): def handle_callback(self, params):
last_sent_time = params['#sent_time'] last_sent_time = params['#sent_time']
if last_sent_time >= self.min_query_time: if last_sent_time >= self.min_query_time and self.response is None:
self.response = params self.response = params
self.serial.reactor.register_async_callback(self.do_wake)
def do_wake(self, eventtime):
self.mutex.unlock()
def get_response(self): def get_response(self):
eventtime = self.serial.reactor.monotonic() with self.mutex:
while self.response is None: pass
eventtime = self.serial.reactor.pause(eventtime + 0.05) if self.response is None:
if eventtime > self.min_query_time + self.TIMEOUT_TIME: raise error("Timeout on wait for '%s' response" % (self.name,))
self.unregister()
raise error("Timeout on wait for '%s' response" % (self.name,))
self.unregister() self.unregister()
return self.response return self.response