From a57cd4c877a6d3eca1bb3d98062bcdf0e2fc47c8 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 16 Jul 2020 01:34:36 +0200 Subject: [PATCH] Add thread-safe lock for _state and _*_handler's modifications fixes https://github.com/syrusakbary/promise/issues/87 --- promise/promise.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/promise/promise.py b/promise/promise.py index ef9a45f..7390deb 100644 --- a/promise/promise.py +++ b/promise/promise.py @@ -1,7 +1,7 @@ from collections import namedtuple from functools import partial, wraps from sys import version_info, exc_info -from threading import RLock +from threading import Lock from types import TracebackType from weakref import WeakKeyDictionary @@ -43,6 +43,8 @@ async_instance = Async() +_state_lock = Lock() + def get_default_scheduler(): # type: () -> ImmediateScheduler @@ -232,8 +234,9 @@ def _fulfill(self, value): err = make_self_resolution_error() # self._attach_extratrace(err) return self._reject(err) - self._state = STATE_FULFILLED - self._rejection_handler0 = value + with _state_lock: + self._state = STATE_FULFILLED + self._rejection_handler0 = value if self._length > 0: if self._is_async_guaranteed: @@ -243,9 +246,10 @@ def _fulfill(self, value): def _reject(self, reason, traceback=None): # type: (Exception, Optional[TracebackType]) -> None - self._state = STATE_REJECTED - self._fulfillment_handler0 = reason - self._traceback = traceback + with _state_lock: + self._state = STATE_REJECTED + self._fulfillment_handler0 = reason + self._traceback = traceback if self._is_final: assert self._length == 0 @@ -507,13 +511,13 @@ def _wait(self, timeout=None): def get(self, timeout=None): # type: (Optional[float]) -> T - target = self._target() self._wait(timeout or DEFAULT_TIMEOUT) return self._target_settled_value(_raise=True) def _target_settled_value(self, _raise=False): # type: (bool) -> Any - return self._target()._settled_value(_raise) + with _state_lock: + return self._target()._settled_value(_raise) _value = _reason = _target_settled_value value = reason = property(_target_settled_value) @@ -570,12 +574,14 @@ def _then( ): # type: (...) -> Promise[S] promise = self.__class__() # type: Promise - target = self._target() - state = target._state - if state == STATE_PENDING: - target._add_callbacks(did_fulfill, did_reject, promise) - else: + with _state_lock: + target = self._target() + state = target._state + if state == STATE_PENDING: + target._add_callbacks(did_fulfill, did_reject, promise) + + if state != STATE_PENDING: traceback = None if state == STATE_FULFILLED: value = target._rejection_handler0