Skip to content
This repository has been archived by the owner on Nov 12, 2022. It is now read-only.

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 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.

bors-servo pushed 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
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 pushed 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 asajeffrey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📌 Commit c8c1453 has been approved by asajeffrey

@bors-servo
Copy link
Contributor

⌛ Testing commit c8c1453 with merge 9b0d063...

bors-servo pushed 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

☀️ 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
bors-servo pushed 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 pushed 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 subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants