-
Notifications
You must be signed in to change notification settings - Fork 10
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
Only one thread can access the same context at a given time #25
Comments
One of the primary reasons this library is not yet stable is specifically due to its handling of execution in multi-threaded environments. This is indeed an issue, and using an I personally believe multiple contexts per runtime is a common use case. I have used it to isolate the execution environments between different "plugins" within the same runtime. The current context implementation, as you may have noticed, acts as a stack, albeit I'm not certain this implementation is the one preferred. |
OT: It's a good crate! It's been working pretty great for me. Thanks for the hard work on it :) Oh maybe multiple contexts is a common thing. I'm assuming too much. In V8, there's a A similar logic would probably work well here. Locking for every context use might get very slow and impractical (for nested uses of the same context for example.) |
Thanks for the kind words :) That's actually a great suggestion, a ReentrantMutex might just be the solution for this use case. I'll see if I can come up with a viable implementation. |
Oh, yes, that's the one! I didn't know how that kind of mutex was called. |
Implemented this locally. Seems to help, but I'm not sure how to handle all the I suppose it would be possible to have a hash map of |
It would require a bit of an overhaul. Data can be associated with each context (see |
I'm currently testing this with a tokio multi-threaded event loop. I made a setTimeout native function that uses it. I added a lazy_static hash map like: lazy_static! {
static ref CONTEXT_MUTEXES: Mutex<HashMap<JsRef, ReentrantMutex<()>>> =
Mutex::new(HashMap::new());
} and I've changed /// Sets the current context.
fn enter(&self) -> Result<()> {
let mutexes = CONTEXT_MUTEXES.lock().unwrap();
match mutexes.get(&self.as_raw()) {
Some(m) => {
let _guard = m.lock();
jstry(unsafe { JsSetCurrentContext(self.as_raw()) })
}
None => panic!("mutex necessary"),
}
} I insert the mutex in I believe the mutex works as intended, unfortunately I still get frequent I'm not sure how it's possible given this mutex!
All contexts? I think it has to be per-context. I might be wrong about that though. Does the user data need to be context guarded to be accessed? If not, we could definitely use that for the mutex. If the user data functions needs to be guarded by the context guard, I'm not sure it's possible to it to store the mutex since we need to mutex to guard the context. Unless I misunderstand 😄 This is the kind of backtrace I get:
|
In your case, the mutexts only lock the thread during the execution of From my understanding, only one context can be used at a time, from any thread. If that is the case, an |
Whoops, that's right. My brain must've been fried.
I think that might be per I'm not sure about all of that, I'm asking around in https://gitter.im/Microsoft/ChakraCore |
Sorry for being a bit vague, I meant of course that the |
No worries, you weren't. I have a specific use-case in mind that uses multiple runtimes and a single context per runtime. A multi-threaded http server passing requests to Chakra. It uses a multi-threaded event loop. If you'd like, I'm happy to implement this change with some guidance. Which reminds me I should probably create 1-2 PRs. Locally, I have a more complete Promise API implementation as well as a partial ES Modules implementation. |
From Gitter: https://gitter.im/Microsoft/ChakraCore?at=5b757c64a6af14730b433141 TL;DR: only 1 context can be active per thread at any given time, regardless of which runtime it belongs to. This means we'd need to share a mutex across all contexts (regardless of runtime.) |
This was definitely a bit unexpected. With that said, a mutex across all contexts should not be required. It's enough to use thread-local variable (TLS) which tracks the active runtime on the current thread, combined with a shared |
I'm not sure the Runtime matters here. Looks like it's only a Context thing. Brain dump:
|
I fixed the issue for my own use case. Using tokio 0.1.8 (just released). For every runtime:
|
This was non-obvious to me since I have experience with V8 which takes care of synchronization for you.
Before setting a context, you might need to unset the current one. Which is what your ContextGuard does as it is dropped. Except it doesn't prevent another thread from trying to set the same context concurrently.
I was thinking an
Arc<Mutex<()>>
might work for entering a context.I'm not sure what's the logic with setting the "previous" context as the current context from the
Context#exit
method. I'm assuming people won't be using more than 1 context per runtime, so inner guards are probably infrequent.Any ideas?
The text was updated successfully, but these errors were encountered: