The strategy for obtaining locks is that we first, for a given time,
only try to get locks when all locks are available in order not to
hold unused resources. After a certain time, however, we need to make
sure that we eventually get all the locks we need. This is done by
holding all locks obtained so far. In order for this strategy to work,
however, also the locks of every level need to be obtained sequentially.
Otherwise, if two locks at a level are requested, other processes might still
starve us.

Signed-off-by: Klaus Aehlig <[email protected]>
---
 lib/mcpu.py | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/lib/mcpu.py b/lib/mcpu.py
index b78b141..7e061cd 100644
--- a/lib/mcpu.py
+++ b/lib/mcpu.py
@@ -379,6 +379,9 @@ class Processor(object):
 
     names = _LockList(names)
 
+    # For locks of the same level, the lock order is lexicographic
+    names.sort()
+
     levelname = locking.LEVEL_NAMES[level]
 
     locks = ["%s/%s" % (levelname, lock) for lock in list(names)]
@@ -399,13 +402,19 @@ class Processor(object):
       locks = self.wconfd.Client().OpportunisticLockUnion(self._wconfdcontext,
                                                           request)
     elif timeout is None:
-      self.wconfd.Client().UpdateLocksWaiting(self._wconfdcontext, priority,
-                                              request)
-      while True:
-        pending = self.wconfd.Client().HasPendingRequest(self._wconfdcontext)
-        if not pending:
-          break
-        time.sleep(10.0 * random.random())
+      logging.info("Definitely requesting %s for %s",
+                   request, self._wconfdcontext)
+      ## The only way to be sure of not getting starved is to sequentially
+      ## acquire the locks one by one (in lock order).
+      for r in request:
+        logging.debug("Definite request %s for %s", r, self._wconfdcontext)
+        self.wconfd.Client().UpdateLocksWaiting(self._wconfdcontext, priority,
+                                                [r])
+        while True:
+          pending = self.wconfd.Client().HasPendingRequest(self._wconfdcontext)
+          if not pending:
+            break
+          time.sleep(10.0 * random.random())
     else:
       logging.debug("Trying %ss to request %s for %s",
                     timeout, request, self._wconfdcontext)
-- 
2.0.0.526.g5318336

Reply via email to