Skip to content

Conversation

asajeffrey
Copy link

IPC channels are reentrant, in that if we call c.send(a) and serializing a calls c.send(b), then the channel contents are b then a. (This comes up in the case of logging over channels, since serialization may include logging.)

This PR adds a unit test to make sure we don't break reentrancy.

Discussion with @nox on IRC.

@asajeffrey
Copy link
Author

cc @pcwalton

src/test.rs Outdated
#[derive(Clone, Debug, Eq, PartialEq)]
struct HasWeirdSerializer (Option<String>);

lazy_static! { static ref WEIRD_CHANNEL: (IpcSender<HasWeirdSerializer>, IpcReceiver<HasWeirdSerializer>) = ipc::channel().unwrap(); }
Copy link
Contributor

@antrik antrik Aug 9, 2016

Choose a reason for hiding this comment

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

A non-reentrant testcase for reentrance? Now that's just lazy! ;-)

I guess it's not really a problem, unless the test harness ever grows an ability to run the same test multiple times in parallel, which seems rather hypothetical...

@antrik
Copy link
Contributor

antrik commented Aug 9, 2016

For what it's worth, this looks good to me.

(I'm happy to see a testcase being added for obscure behaviour someone will be relying on -- a very good practice that probably should be employed more often :-) )

@jdm
Copy link
Member

jdm commented Aug 9, 2016

Travis is displeased:

     Running `rustc src/lib.rs --crate-name ipc_channel -g --test -C metadata=f57b0507e715624e -C extra-filename=-f57b0507e715624e --out-dir /Users/travis/build/servo/ipc-channel/target/debug/deps --emit=dep-info,link -L dependency=/Users/travis/build/servo/ipc-channel/target/debug/deps --extern rand=/Users/travis/build/servo/ipc-channel/target/debug/deps/librand-49a08859d086fffe.rlib --extern lazy_static=/Users/travis/build/servo/ipc-channel/target/debug/deps/liblazy_static-359f5533c970cd71.rlib --extern crossbeam=/Users/travis/build/servo/ipc-channel/target/debug/deps/libcrossbeam-95e5cb210400af41.rlib --extern bincode=/Users/travis/build/servo/ipc-channel/target/debug/deps/libbincode-6bdca1673f724e3d.rlib --extern libc=/Users/travis/build/servo/ipc-channel/target/debug/deps/liblibc-1bd8847afb79f283.rlib --extern serde=/Users/travis/build/servo/ipc-channel/target/debug/deps/libserde-652fd324488db42d.rlib`

<lazy_static macros>:2:32: 3:65 error: the trait bound `std::cell::Cell<u32>: std::marker::Sync` is not satisfied [E0277]

<lazy_static macros>:2 use std :: sync :: ONCE_INIT ; static mut $ NAME : $ crate :: lazy :: Lazy < $

                                                      ^

<lazy_static macros>:21:1: 21:40 note: in this expansion of __lazy_static_create! (defined in <lazy_static macros>)

<lazy_static macros>:4:1: 5:75 note: in this expansion of lazy_static! (defined in <lazy_static macros>)

src/test.rs:56:1: 56:135 note: in this expansion of lazy_static! (defined in <lazy_static macros>)

<lazy_static macros>:2:32: 3:65 help: run `rustc --explain E0277` to see a detailed explanation

<lazy_static macros>:2:32: 3:65 note: `std::cell::Cell<u32>` cannot be shared between threads safely 

<lazy_static macros>:2:32: 3:65 note: required because it appears within the type `platform::os::OsIpcReceiver` 

<lazy_static macros>:2:32: 3:65 note: required because it appears within the type `ipc::IpcReceiver<test::HasWeirdSerializer>` 

<lazy_static macros>:2:32: 3:65 note: required because it appears within the type `(ipc::IpcSender<test::HasWeirdSerializer>, ipc::IpcReceiver<test::HasWeirdSerializer>)` 

<lazy_static macros>:2:32: 3:65 note: required by `lazy_static::lazy::Lazy` 

error: aborting due to previous error 

error: Could not compile `ipc-channel`.

@asajeffrey
Copy link
Author

Not sure why I'm not getting this error on my end... I'll put it in a rw mutex or some such and retry.

@antrik
Copy link
Contributor

antrik commented Aug 10, 2016

@asajeffrey on what platform(s) have you tested this? The definition of IpcReceiver is presently kinda wrong on the linux and inprocess backends (only the macos one gets it right): the definitions formally look thread-safe, which is not really true -- see discussion on #89 . I have some work in progress to fix this, which I haven't quite wrapped up yet; but once that's in, your code would fail equally on all platforms.

@asajeffrey
Copy link
Author

The test isn't to see if it's thread-safe, it's to see if it's reentrant. Since IPC channels serialize to a fresh buffer each time, it should be reentrant.

@antrik
Copy link
Contributor

antrik commented Aug 10, 2016

@asajeffrey well, that's not what the test is about -- but since lazy_static creates a global variable, Rust enforces that whatever it holds must be thread-safe. That's not really the case for IpcReceiver.

@asajeffrey
Copy link
Author

Indeed, since it's a global it has to be sync. Rather ironically this is exactly the use case for reentrant locks, which is what got is here in the first place. Probably easiest just to make it thread-local. I'm not at my desk today, I'll do this tomorrow.

@asajeffrey
Copy link
Author

I made Travis happy by making the global thread-local.

src/test.rs Outdated
Ok(HasWeirdSerializer(try!(Deserialize::deserialize(deserializer))))
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Personally I think it would be more readable to put all this stuff right before the (only) test case using it...

Copy link
Author

Choose a reason for hiding this comment

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

Fair enough.

@antrik
Copy link
Contributor

antrik commented Aug 15, 2016

@asajeffrey thanks :-) Please squash the commits -- and then we just need someone with official reviewer status to approve it...

@asajeffrey
Copy link
Author

Squashed.

@antrik
Copy link
Contributor

antrik commented Aug 15, 2016

Meh, there is an intermittent failure it seems? This definitely shouldn't be affected by these changes...

@asajeffrey
Copy link
Author

Yes, that is odd... timeouts on unrelated tests?

@antrik
Copy link
Contributor

antrik commented Aug 20, 2016

Just to be clear: I really don't think this test failure has anything to do with this PR. Either the test case in question has intermittent failures, or there was some one-time hiccup on Travis.

@pcwalton r?

@bors-servo
Copy link
Contributor

☔ The latest upstream changes (presumably #92) made this pull request unmergeable. Please resolve the merge conflicts.

@pcwalton
Copy link
Contributor

Looks good once the conflicts are resolved.

@asajeffrey asajeffrey force-pushed the master branch 2 times, most recently from 36af002 to 525f6d6 Compare September 5, 2016 13:50
@asajeffrey
Copy link
Author

@bors-servo r=pcwalton

@bors-servo
Copy link
Contributor

📌 Commit 3a06775 has been approved by pcwalton

@bors-servo
Copy link
Contributor

⌛ Testing commit 3a06775 with merge ca63fdb...

bors-servo pushed a commit that referenced this pull request Sep 5, 2016
Added unit test for reentrancy.

IPC channels are reentrant, in that if we call `c.send(a)` and serializing `a` calls `c.send(b)`, then the channel contents are `b` then `a`. (This comes up in the case of logging over channels, since serialization may include logging.)

This PR adds a unit test to make sure we don't break reentrancy.

Discussion with @nox on IRC.
@bors-servo
Copy link
Contributor

☀️ Test successful - status-appveyor, status-travis

@bors-servo bors-servo merged commit 3a06775 into servo:master Sep 5, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants