Skip to content

Commit

Permalink
Don't call callbacks when holding _handlers_lock (#258)
Browse files Browse the repository at this point in the history
Closes #255

Background:
#239 adds the lock _handlers_lock:

python-zeroconf/zeroconf/__init__.py

    self._handlers_lock = threading.Lock()  # ensure we process a full message in one go 

Which is used in the engine thread:

     def handle_response(self, msg: DNSIncoming) -> None: 
         """Deal with incoming response packets.  All answers 
         are held in the cache, and listeners are notified.""" 
  
         with self._handlers_lock: 
  

And also by the service browser when issuing the state change callbacks:

 if len(self._handlers_to_call) > 0 and not self.zc.done: 
     with self.zc._handlers_lock: 
         handler = self._handlers_to_call.popitem(False) 
         self._service_state_changed.fire( 
             zeroconf=self.zc, service_type=self.type, name=handler[0], state_change=handler[1] 
         ) 

Both pychromecast and Home Assistant calls Zeroconf.get_service_info from the service callbacks which means the lock may be held for several seconds which will starve the engine thread.
  • Loading branch information
emontnemery committed May 26, 2020
1 parent 54d116f commit fe86566
Showing 1 changed file with 6 additions and 6 deletions.
12 changes: 6 additions & 6 deletions zeroconf/__init__.py
Expand Up @@ -1585,12 +1585,12 @@ def run(self) -> None:
if len(self._handlers_to_call) > 0 and not self.zc.done:
with self.zc._handlers_lock:
(name, service_type_state_change) = self._handlers_to_call.popitem(False)
self._service_state_changed.fire(
zeroconf=self.zc,
service_type=service_type_state_change[0],
name=name,
state_change=service_type_state_change[1],
)
self._service_state_changed.fire(
zeroconf=self.zc,
service_type=service_type_state_change[0],
name=name,
state_change=service_type_state_change[1],
)


class ServiceInfo(RecordUpdateListener):
Expand Down

0 comments on commit fe86566

Please sign in to comment.