Skip to content
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

Prevent initializing and shutting down SpiderMonkey from different threads #487

Merged
merged 2 commits into from Nov 26, 2019

Conversation

@jdm
Copy link
Member

jdm commented Nov 23, 2019

Based on this comment, it appears that JS_Init and JS_ShutDown need to be called on the same thread. These changes make JSEngine a non-sendable type, and add JSEngineHandle as a sendable type that allows verifying that all outstanding consumers of the engine are dropped before shutting down.

@jdm jdm mentioned this pull request Nov 23, 2019
4 of 4 tasks complete
bors-servo added a commit to servo/servo that referenced this pull request Nov 23, 2019
Ensure SpiderMonkey shuts down cleanly

These changes (along with servo/rust-mozjs#487) ensure that the JS engine is initialized on a thread which is kept alive until the end of the program, when we can safely shut down the engine.

---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #21696 and fix #22276
- [x] There are tests for these changes
@jdm
Copy link
Member Author

jdm commented Nov 23, 2019

Note to self: need to update unit tests.

@gterzian
Copy link
Member

gterzian commented Nov 24, 2019

To elaborate on servo/servo#24845 (comment)

I think you could make outstanding_handles: Arc<AtomicU32> into a outstanding_handles: Arc<(Mutex<EngineHandles>, Condvar)>.

with EngineHandles being:

enum EngineHandles {
    /// Initial state, equivalent to 0 handles, but before any handles have been created.
    Initialized,
    /// Count handles, start at 1, goes to 0 when all handles are dropped.
    Count(u32)
}

with can_shutdown containing the equivalent of while outstanding_handles != EngineHandles::Count(0) {//wait on the condvar}.

So that the thread in script can then block on that call, and then shutdown.

pub struct JSEngine {
/// The count of alive handles derived from this initialized instance.
outstanding_handles: Arc<AtomicU32>,
// Ensure this type cannot be sent between threads.

This comment has been minimized.

@gterzian

gterzian Nov 24, 2019

Member

Could impl !Send for JSEngine{} be used for that purpose?

This comment has been minimized.

@jdm

jdm Nov 25, 2019

Author Member
error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now
   --> src/rust.rs:181:1
    |
181 | impl !Send for JSEngine {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/13231
    = help: add `#![feature(optin_builtin_traits)]` to the crate attributes to enable

I'd rather not introduce nightly-only features to this crate.

@jdm jdm mentioned this pull request Nov 25, 2019
4 of 4 tasks complete
@jdm
Copy link
Member Author

jdm commented Nov 25, 2019

The idea of making shutdown be a blocking operation is interesting, but I think I'd rather not make that a requirement of using this crate. It's not difficult to imagine a consumer writing code that uses this API that ends up creating a deadlock by not ensuring that all of the engine handles are disposed of before attempting to shutdown. I would rather provide an API that panics by default and allow consumers to build their own blocking shutdown behaviour on top of it, like servo/servo#24862 does for Servo.

bors-servo added a commit to servo/servo that referenced this pull request Nov 25, 2019
Ensure SpiderMonkey shuts down cleanly

This is the alternate solution that I described in #24845. Given how much simpler the resulting code is, I'm now much more in favour of this design. Depends on servo/rust-mozjs#487.

---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #21696 and fix #22276
- [x] There are tests for these changes
@gterzian
Copy link
Member

gterzian commented Nov 26, 2019

I would rather provide an API that panics by default and allow consumers to build their own blocking shutdown behaviour on top of it

Yes that makes sense, although it's not clear to me how a non-blocking use, or a blocking use that isn't a spinlock waiting for it to return true, would look like.

It would be possible for a consumer to deadlock on a blocking shutdown operation, and such deadlock is likely to be not intermittent and quickly fixed. On the other hand, a non-blocking can_shutdown could lead to intermittent issues.

I guess either way for the API could be a valid choice thought...

Copy link
Member

asajeffrey left a comment

Is it worth dedicating a thread to JS engine creation and destruction? That would make the API a bit cleaner, but at the cost of yet another thread. I'll leave that up to you, this implementation LGTM.

@jdm
Copy link
Member Author

jdm commented Nov 26, 2019

@bors-servo r=asajeffrey

@bors-servo
Copy link
Contributor

bors-servo commented Nov 26, 2019

📌 Commit c8c1453 has been approved by asajeffrey

@bors-servo
Copy link
Contributor

bors-servo commented Nov 26, 2019

Testing commit c8c1453 with merge 9b0d063...

bors-servo added a commit that referenced this pull request Nov 26, 2019
Prevent initializing and shutting down SpiderMonkey from different threads

Based on [this comment](https://github.com/servo/mozjs/blob/e21c05b415dfc246175ff8d5fc48b0e8c5b4e9e9/mozjs/js/public/Initialization.h#L19-L23), it appears that JS_Init and JS_ShutDown need to be called on the same thread. These changes make JSEngine a non-sendable type, and add JSEngineHandle as a sendable type that allows verifying that all outstanding consumers of the engine are dropped before shutting down.
@bors-servo
Copy link
Contributor

bors-servo commented Nov 26, 2019

☀️ Test successful - checks-travis, status-appveyor
Approved by: asajeffrey
Pushing 9b0d063 to master...

@bors-servo bors-servo merged commit c8c1453 into servo:master Nov 26, 2019
3 checks passed
3 checks passed
Travis CI - Pull Request Build Passed
Details
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
homu Test successful
Details
bors-servo added a commit to servo/servo that referenced this pull request Nov 27, 2019
Ensure SpiderMonkey shuts down cleanly

This is the alternate solution that I described in #24845. Given how much simpler the resulting code is, I'm now much more in favour of this design. Depends on servo/rust-mozjs#487.

---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #21696 and fix #22276
- [x] There are tests for these changes
bors-servo added a commit to servo/servo that referenced this pull request Nov 27, 2019
Ensure SpiderMonkey shuts down cleanly

This is the alternate solution that I described in #24845. Given how much simpler the resulting code is, I'm now much more in favour of this design. Depends on servo/rust-mozjs#487.

---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #21696 and fix #22276
- [x] There are tests for these changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants
You can’t perform that action at this time.