Add python-eventlet package to MOS 8.0 repository
[packages/trusty/python-eventlet.git] / python-eventlet / eventlet / semaphore.py
similarity index 90%
rename from eventlet/eventlet/semaphore.py
rename to python-eventlet/eventlet/semaphore.py
index 73dbbc15a32c48057e4d1388115916077f30127c..b2ef9d34f78e7c37b31a8079f392accb40491f54 100644 (file)
@@ -1,4 +1,7 @@
 from __future__ import with_statement
+
+import collections
+
 from eventlet import greenthread
 from eventlet import hubs
 from eventlet.timeout import Timeout
@@ -35,7 +38,7 @@ class Semaphore(object):
         if value < 0:
             raise ValueError("Semaphore must be initialized with a positive "
                              "number, got %s" % value)
-        self._waiters = set()
+        self._waiters = collections.deque()
 
     def __repr__(self):
         params = (self.__class__.__name__, hex(id(self)),
@@ -75,13 +78,25 @@ class Semaphore(object):
         When invoked with blocking set to false, do not block. If a call without
         an argument would block, return false immediately; otherwise, do the
         same thing as when called without arguments, and return true.
+
+        Timeout value must be strictly positive.
         """
-        if not blocking and timeout is not None:
-            raise ValueError("can't specify timeout for non-blocking acquire")
+        if timeout == -1:
+            timeout = None
+        if timeout is not None and timeout < 0:
+            raise ValueError("timeout value must be strictly positive")
+        if not blocking:
+            if timeout is not None:
+                raise ValueError("can't specify timeout for non-blocking acquire")
+            timeout = 0
         if not blocking and self.locked():
             return False
-        if self.counter <= 0:
-            self._waiters.add(greenthread.getcurrent())
+
+        current_thread = greenthread.getcurrent()
+
+        if self.counter <= 0 or self._waiters:
+            if current_thread not in self._waiters:
+                self._waiters.append(current_thread)
             try:
                 if timeout is not None:
                     ok = False
@@ -92,10 +107,19 @@ class Semaphore(object):
                     if not ok:
                         return False
                 else:
-                    while self.counter <= 0:
+                    # If someone else is already in this wait loop, give them
+                    # a chance to get out.
+                    while True:
                         hubs.get_hub().switch()
+                        if self.counter > 0:
+                            break
             finally:
-                self._waiters.discard(greenthread.getcurrent())
+                try:
+                    self._waiters.remove(current_thread)
+                except ValueError:
+                    # Fine if its already been dropped.
+                    pass
+
         self.counter -= 1
         return True
 
@@ -117,7 +141,7 @@ class Semaphore(object):
 
     def _do_acquire(self):
         if self._waiters and self.counter > 0:
-            waiter = self._waiters.pop()
+            waiter = self._waiters.popleft()
             waiter.switch()
 
     def __exit__(self, typ, val, tb):