Revision 7e8841bd

b/lib/locking.py
52 52
  return wrap
53 53

  
54 54

  
55
class RunningTimeout(object):
56
  """Class to calculate remaining timeout when doing several operations.
57

  
58
  """
59
  __slots__ = [
60
    "_allow_negative",
61
    "_start_time",
62
    "_time_fn",
63
    "_timeout",
64
    ]
65

  
66
  def __init__(self, timeout, allow_negative, _time_fn=time.time):
67
    """Initializes this class.
68

  
69
    @type timeout: float
70
    @param timeout: Timeout duration
71
    @type allow_negative: bool
72
    @param allow_negative: Whether to return values below zero
73
    @param _time_fn: Time function for unittests
74

  
75
    """
76
    object.__init__(self)
77

  
78
    if timeout is not None and timeout < 0.0:
79
      raise ValueError("Timeout must not be negative")
80

  
81
    self._timeout = timeout
82
    self._allow_negative = allow_negative
83
    self._time_fn = _time_fn
84

  
85
    self._start_time = None
86

  
87
  def Remaining(self):
88
    """Returns the remaining timeout.
89

  
90
    """
91
    if self._timeout is None:
92
      return None
93

  
94
    # Get start time on first calculation
95
    if self._start_time is None:
96
      self._start_time = self._time_fn()
97

  
98
    # Calculate remaining time
99
    remaining_timeout = self._start_time + self._timeout - self._time_fn()
100

  
101
    if not self._allow_negative:
102
      # Ensure timeout is always >= 0
103
      return max(0.0, remaining_timeout)
104

  
105
    return remaining_timeout
106

  
107

  
55 108
class _SingleNotifyPipeConditionWaiter(object):
56 109
  """Helper class for SingleNotifyPipeCondition
57 110

  
......
777 830

  
778 831
    # We need to keep track of how long we spent waiting for a lock. The
779 832
    # timeout passed to this function is over all lock acquires.
780
    remaining_timeout = timeout
781
    if timeout is None:
782
      start = None
783
      calc_remaining_timeout = lambda: None
784
    else:
785
      start = time.time()
786
      calc_remaining_timeout = lambda: max(0.0, (start + timeout) - time.time())
833
    running_timeout = RunningTimeout(timeout, False)
787 834

  
788 835
    try:
789 836
      if names is not None:
......
794 841
          names = sorted(names)
795 842

  
796 843
        return self.__acquire_inner(names, False, shared,
797
                                    calc_remaining_timeout, test_notify)
844
                                    running_timeout.Remaining, test_notify)
798 845

  
799 846
      else:
800 847
        # If no names are given acquire the whole set by not letting new names
......
807 854
        # anyway, though, so we'll get the list lock exclusively as well in
808 855
        # order to be able to do add() on the set while owning it.
809 856
        if not self.__lock.acquire(shared=shared,
810
                                   timeout=calc_remaining_timeout()):
857
                                   timeout=running_timeout.Remaining()):
811 858
          raise _AcquireTimeout()
812 859
        try:
813 860
          # note we own the set-lock
814 861
          self._add_owned()
815 862

  
816 863
          return self.__acquire_inner(self.__names(), True, shared,
817
                                      calc_remaining_timeout, test_notify)
864
                                      running_timeout.Remaining, test_notify)
818 865
        except:
819 866
          # We shouldn't have problems adding the lock to the owners list, but
820 867
          # if we did we'll try to release this lock and re-raise exception.
......
827 874
      return None
828 875

  
829 876
  def __acquire_inner(self, names, want_all, shared, timeout_fn, test_notify):
830
    """
877
    """Inner logic for acquiring a number of locks.
878

  
879
    @param names: Names of the locks to be acquired
880
    @param want_all: Whether all locks in the set should be acquired
881
    @param shared: Whether to acquire in shared mode
882
    @param timeout_fn: Function returning remaining timeout
883
    @param test_notify: Special callback function for unittesting
831 884

  
832 885
    """
833 886
    acquire_list = []
......
863 916
          test_notify_fn = None
864 917

  
865 918
        timeout = timeout_fn()
866
        if timeout is not None and timeout < 0:
867
          raise _AcquireTimeout()
868 919

  
869 920
        try:
870 921
          # raises LockError if the lock was deleted

Also available in: Unified diff