-
Notifications
You must be signed in to change notification settings - Fork 328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix context lock removal #10273
Fix context lock removal #10273
Conversation
Removal of context lock assumed that one still holds a lock on it. This is no longer the case when using a `withContextLock` block that correctly manages the resource. This change fixes the `IllegalMonitorStateException`. Closes #10354.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The context lock is automatically created by withContextLock
- why it is not cleaned at the end of the withContextLock
method? That's the intended behavior of withXyz
methods - we should delete the removeContextLock
method.
@@ -248,7 +248,10 @@ class ReentrantLocking(logger: TruffleLogger) extends Locking { | |||
contextMapLock.lock() | |||
try { | |||
if (contextLocks.contains(contextId)) { | |||
contextLocks(contextId).unlock() | |||
assertNotLocked( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the desired behavior. Why do we have removeContextLock
at all? Because of this line? Then just remove it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I suppose it was added to avoid creating new instances of ReentrantLock
. Once the lock is created it is re-used. It saves roughly 10ms per command (as that particular lock is required quite often).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everywhere, where ctx.locking.withContextLock(
is used, there is an instance of RuntimeContext
. To
avoid creating new instances of ReentrantLock
the RuntimeContext
shall obtain some object instance via ctx.locking.createContextLock
and then use it via ctx.locking.withContextLock(
until it is needed. At the end it should close it (removeContextLock
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible API could look like:
diff --git engine/runtime-instrument-common/src/main/java/org/enso/interpreter/instrument/execution/Locking.java engine/runtime-instrument-common/src/main/java/org/enso/interpreter/instrument/execution/Locking.java
index fc6e3f6389..b223ce34fb 100644
--- engine/runtime-instrument-common/src/main/java/org/enso/interpreter/instrument/execution/Locking.java
+++ engine/runtime-instrument-common/src/main/java/org/enso/interpreter/instrument/execution/Locking.java
@@ -37,21 +37,25 @@ public interface Locking {
<T> T withPendingEditsLock(Class<?> where, Callable<T> callable);
/**
- * Executes `callable` while holding a context lock
+ * Allocates new handle for use in {@link #withContextLock} associated with given context ID.
*
- * @param contextId context id for which the lock is being requested
- * @param where the class requesting the lock
- * @param callable code to be executed while holding the lock
- * @return the result of calling `callable` or null, if no result is expected
+ * @param contextId context ID
+ * @return an object to pass to {@link #withContextLock} and to {@link AutoCloseable#close()} when
+ * no longer needed
*/
- <T> T withContextLock(UUID contextId, Class<?> where, Callable<T> callable);
+ AutoCloseable createContextLock(UUID contextId);
/**
- * Removes a context lock.
+ * Executes `callable` while holding a context lock
*
- * @param contextId a context to remove
+ * @param contextLockHandle handle created by {@link #createContextLock(UUID)}
+ * @param where the class requesting the lock
+ * @param callable code to be executed while holding the lock
+ * @return the result of calling `callable` or null, if no result is expected
+ * @throws ClassCastException if {@code contextLockHandle} isn't coming from {@link
+ * #createContextLock(UUID)}
*/
- void removeContextLock(UUID contextId);
+ <T> T withContextLock(AutoCloseable contextLockHandle, Class<?> where, Callable<T> callable);
/**
* Executes `callable` while holding a file lock
More advanced tricks with generics (to hide ClassCastException
from the docs) are possible, but probably unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hopefully the AutoCloseable
solution will be easy to implement.
Tried to address your comment @JaroslavTulach, didn't really see the need for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unblocking.
Pull Request Description
Removal of context lock assumed that one still holds a lock on it. This is no longer the case when using a
withContextLock
block that correctly manages the resource. This change fixes theIllegalMonitorStateException
.Closes #10254.
Checklist
Please ensure that the following checklist has been satisfied before submitting the PR:
Scala,
Java,
TypeScript,
and
Rust
style guides. In case you are using a language not listed above, follow the Rust style guide.