Skip to content

Commit 8bff944

Browse files
Make message Muts Send
This was previously held back due to concerns about difficulty in supporting `mut splitting` apis, where an API could hand out simultaneous muts to 'disjoint' submessages, which is problematic. We don't have mut splitting APIs today but now believe we could find a way to safely support it when we add it while allowing Muts to be Send, and so this does so now. PiperOrigin-RevId: 802712451
1 parent 76e13d9 commit 8bff944

3 files changed

Lines changed: 81 additions & 2 deletions

File tree

rust/test/shared/BUILD

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,3 +606,31 @@ rust_test(
606606
"@crate_index//:googletest",
607607
],
608608
)
609+
610+
rust_test(
611+
name = "threading_test_cpp",
612+
srcs = ["threading_test.rs"],
613+
aliases = {
614+
"//rust:protobuf_cpp_export": "protobuf",
615+
},
616+
rustc_flags = ["--cfg=bzl"],
617+
deps = [
618+
"//rust:protobuf_cpp_export",
619+
"//rust/test:unittest_cpp_rust_proto",
620+
"@crate_index//:googletest",
621+
],
622+
)
623+
624+
rust_test(
625+
name = "threading_test_upb",
626+
srcs = ["threading_test.rs"],
627+
aliases = {
628+
"//rust:protobuf_upb_export": "protobuf",
629+
},
630+
rustc_flags = ["--cfg=bzl"],
631+
deps = [
632+
"//rust:protobuf_upb_export",
633+
"//rust/test:unittest_upb_rust_proto",
634+
"@crate_index//:googletest",
635+
],
636+
)

rust/test/shared/threading_test.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Protocol Buffers - Google's data interchange format
2+
// Copyright 2023 Google LLC. All rights reserved.
3+
//
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file or at
6+
// https://developers.google.com/open-source/licenses/bsd
7+
8+
#[cfg(not(bzl))]
9+
mod protos;
10+
#[cfg(not(bzl))]
11+
use protos::*;
12+
13+
use googletest::prelude::*;
14+
15+
use std::sync::{Arc, Mutex};
16+
use unittest_rust_proto::TestAllTypes;
17+
18+
#[gtest]
19+
fn test_sending_owned_arc() {
20+
let msg = Arc::new(Mutex::new(TestAllTypes::default()));
21+
22+
let msg_clone = Arc::clone(&msg);
23+
let handle = std::thread::spawn(move || {
24+
let mut locked_msg = msg_clone.lock().unwrap();
25+
locked_msg.set_optional_int32(123);
26+
});
27+
handle.join().unwrap();
28+
29+
let locked_msg = msg.lock().unwrap();
30+
assert_eq!(locked_msg.optional_int32(), 123);
31+
}
32+
33+
#[gtest]
34+
fn test_sending_mut_scoped() {
35+
let mut msg = TestAllTypes::default();
36+
37+
std::thread::scope(|scope| {
38+
let mut child_mut = msg.optional_nested_message_mut();
39+
scope.spawn(move || {
40+
child_mut.set_bb(123);
41+
});
42+
});
43+
44+
assert_eq!(msg.optional_nested_message().bb(), 123);
45+
}

src/google/protobuf/compiler/rust/message.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -741,10 +741,16 @@ void GenerateRs(Context& ctx, const Descriptor& msg, const upb::DefPool& pool) {
741741
$accessor_fns_for_muts$
742742
}
743743
744+
//~ Note that upb Arenas are not threadsafe but we mark `$Msg$Mut` as
745+
//~ both Send and Sync.
746+
//~ We currently ensure safety by designing the API to ensure that no two
747+
//~ threads can hold a reference to MsgMuts with the same arena.
748+
// SAFETY:
749+
// - `$Msg$Mut` does not perform any shared mutation.
750+
unsafe impl Send for $Msg$Mut<'_> {}
751+
744752
// SAFETY:
745753
// - `$Msg$Mut` does not perform any shared mutation.
746-
// - `$Msg$Mut` is not `Send`, and so even in the presence of mutator
747-
// splitting, synchronous access of an arena is impossible.
748754
unsafe impl Sync for $Msg$Mut<'_> {}
749755
750756
impl<'msg> $pb$::Proxy<'msg> for $Msg$Mut<'msg> {}

0 commit comments

Comments
 (0)