Issue #11915: threading.RLock()._release_save() raises a RuntimeError if the
lock was not acquired.
diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py
index ff30d41..3ed61f3 100644
--- a/Lib/test/lock_tests.py
+++ b/Lib/test/lock_tests.py
@@ -247,6 +247,7 @@
         # Cannot release an unacquired lock
         lock = self.locktype()
         self.assertRaises(RuntimeError, lock.release)
+        self.assertRaises(RuntimeError, lock._release_save)
         lock.acquire()
         lock.acquire()
         lock.release()
@@ -254,6 +255,7 @@
         lock.release()
         lock.release()
         self.assertRaises(RuntimeError, lock.release)
+        self.assertRaises(RuntimeError, lock._release_save)
 
     def test_different_thread(self):
         # Cannot release from a different thread
diff --git a/Lib/threading.py b/Lib/threading.py
index eb3cb62..28c2146 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -157,6 +157,8 @@
     def _release_save(self):
         if __debug__:
             self._note("%s._release_save()", self)
+        if self._count == 0:
+            raise RuntimeError("cannot release un-acquired lock")
         count = self._count
         self._count = 0
         owner = self._owner