From 68adfdb2958539f18cea02f08ae9919379fa7dba Mon Sep 17 00:00:00 2001
From: Guido Trotter <ultrotter@google.com>
Date: Tue, 8 Jul 2008 16:32:07 +0000
Subject: [PATCH] Processor: Acquire locks before executing an LU

If we're running in a "new style" LU we may need some locks, as required
by the ExpandNames function, to be able to run. We'll walk up the lock
levels present in the needed_locks dictionary and acquire them, then run
the actual LU. LUs can release some or all the acquired locks, if they
want, before terminating, provided they update their needed_locks
dictionary appropriately, so that we know not to release a level if they
have already done so.

Reviewed-by: iustinp
---
 lib/mcpu.py | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/lib/mcpu.py b/lib/mcpu.py
index 0d9e7037b..4bdfb4671 100644
--- a/lib/mcpu.py
+++ b/lib/mcpu.py
@@ -123,6 +123,29 @@ class Processor(object):
 
     return result
 
+  def _LockAndExecLU(self, lu, level):
+    """Execute a Logical Unit, with the needed locks.
+
+    This is a recursive function that starts locking the given level, and
+    proceeds up, till there are no more locks to acquire. Then it executes the
+    given LU and its opcodes.
+
+    """
+    if level in lu.needed_locks:
+      # This is always safe to do, as we can't acquire more/less locks than
+      # what was requested.
+      lu.needed_locks[level] = self.context.glm.acquire(level,
+                                                        lu.needed_locks[level])
+      try:
+        result = self._LockAndExecLU(lu, level + 1)
+      finally:
+        if lu.needed_locks[level]:
+          self.context.glm.release(level)
+    else:
+      result = self._ExecLU(lu)
+
+    return result
+
   def ExecOpCode(self, op):
     """Execute an opcode.
 
@@ -151,7 +174,8 @@ class Processor(object):
       self.exclusive_BGL = lu_class.REQ_BGL
       lu = lu_class(self, op, self.context, sstore)
       lu.ExpandNames()
-      result = self._ExecLU(lu)
+      assert lu.needed_locks is not None, "needed_locks not set by LU"
+      result = self._LockAndExecLU(lu, locking.LEVEL_NODE)
     finally:
       self.context.glm.release(locking.LEVEL_CLUSTER)
       self.exclusive_BGL = False
-- 
GitLab