Ensure SourceMixin descendents shut down the source prior to closing.
Furthermore, make sure devices are closed before pin factory shuts down,
and that pins have a strong reference to their owning factory (to
prevent losing the factory before the pins).
This commit is contained in:
Dave Jones
2017-06-19 22:22:39 +01:00
parent ab73e857fd
commit bcc94354ea
4 changed files with 25 additions and 4 deletions

View File

@@ -34,6 +34,7 @@ from .exc import (
GPIOPinInUse,
GPIODeviceClosed,
PinFactoryFallback,
PinReservationsExist,
)
from .compat import frozendict
@@ -202,6 +203,20 @@ class Device(ValuesMixin, GPIOBase):
@classmethod
def _set_pin_factory(cls, new_factory):
reserved_devices = {
dev
for ref_list in cls._reservations.values()
for ref in ref_list
for dev in (ref(),)
if dev is not None
}
if new_factory is None:
for dev in reserved_devices:
dev.close()
elif reserved_devices:
raise PinReservationsExist(
"can't change factory while devices still hold pin "
"reservations (%r)" % dev)
if cls._pin_factory is not None:
cls._pin_factory.close()
cls._pin_factory = new_factory

View File

@@ -145,6 +145,9 @@ class PinNoPins(PinError, RuntimeError):
class PinInvalidPin(PinError, ValueError):
"Error raised when an invalid pin specification is provided"
class PinReservationsExist(PinError, RuntimeError):
"Error raised when pin factory is changed while reservations still exist"
class GPIOZeroWarning(Warning):
"Base class for all warnings in GPIO Zero"

View File

@@ -70,10 +70,13 @@ class SourceMixin(object):
def close(self):
try:
super(SourceMixin, self).close()
self.source = None
except AttributeError:
pass
try:
super(SourceMixin, self).close()
except AttributeError:
pass
def _copy_values(self, source):
for v in source:

View File

@@ -9,10 +9,10 @@ str = type('')
import io
from threading import RLock
from types import MethodType
from weakref import ref, proxy
try:
from weakref import WeakMethod
from weakref import ref, WeakMethod
except ImportError:
from ..compat import WeakMethod
import warnings
@@ -216,7 +216,7 @@ class PiPin(Pin):
"""
def __init__(self, factory, number):
super(PiPin, self).__init__()
self._factory = proxy(factory)
self._factory = factory
self._when_changed_lock = RLock()
self._when_changed = None
self._number = number