Single set pointer (#29114)

* Single set pointer

* Update single_set_ptr.h

* fix

* fix

* build

* custom deleters
pull/29125/head^2
Craig Tiller 3 years ago committed by GitHub
parent ccf70cf273
commit 3e5a5bba59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      BUILD
  2. 93
      CMakeLists.txt
  3. 98
      build_autogenerated.yaml
  4. 83
      src/core/lib/gprpp/single_set_ptr.h
  5. 12
      test/core/gprpp/BUILD
  6. 63
      test/core/gprpp/single_set_ptr_test.cc
  7. 24
      tools/run_tests/generated/tests.json

11
BUILD

@ -2235,6 +2235,17 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "single_set_ptr",
hdrs = [
"src/core/lib/gprpp/single_set_ptr.h",
],
language = "c++",
deps = [
"gpr_base",
],
)
grpc_cc_library(
name = "channel_stack_builder",
srcs = [

93
CMakeLists.txt generated

@ -979,6 +979,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx settings_timeout_test)
add_dependencies(buildtests_cxx shutdown_test)
add_dependencies(buildtests_cxx simple_request_bad_client_test)
add_dependencies(buildtests_cxx single_set_ptr_test)
add_dependencies(buildtests_cxx sleep_test)
add_dependencies(buildtests_cxx smoke_test)
add_dependencies(buildtests_cxx sockaddr_utils_test)
@ -14895,6 +14896,98 @@ target_link_libraries(simple_request_bad_client_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(single_set_ptr_test
src/core/ext/upb-generated/google/protobuf/any.upb.c
src/core/ext/upb-generated/google/rpc/status.upb.c
src/core/lib/gpr/alloc.cc
src/core/lib/gpr/atm.cc
src/core/lib/gpr/cpu_iphone.cc
src/core/lib/gpr/cpu_linux.cc
src/core/lib/gpr/cpu_posix.cc
src/core/lib/gpr/cpu_windows.cc
src/core/lib/gpr/env_linux.cc
src/core/lib/gpr/env_posix.cc
src/core/lib/gpr/env_windows.cc
src/core/lib/gpr/log.cc
src/core/lib/gpr/log_android.cc
src/core/lib/gpr/log_linux.cc
src/core/lib/gpr/log_posix.cc
src/core/lib/gpr/log_windows.cc
src/core/lib/gpr/murmur_hash.cc
src/core/lib/gpr/string.cc
src/core/lib/gpr/string_posix.cc
src/core/lib/gpr/string_util_windows.cc
src/core/lib/gpr/string_windows.cc
src/core/lib/gpr/sync.cc
src/core/lib/gpr/sync_abseil.cc
src/core/lib/gpr/sync_posix.cc
src/core/lib/gpr/sync_windows.cc
src/core/lib/gpr/time.cc
src/core/lib/gpr/time_posix.cc
src/core/lib/gpr/time_precise.cc
src/core/lib/gpr/time_windows.cc
src/core/lib/gpr/tmpfile_msys.cc
src/core/lib/gpr/tmpfile_posix.cc
src/core/lib/gpr/tmpfile_windows.cc
src/core/lib/gpr/wrap_memcpy.cc
src/core/lib/gprpp/examine_stack.cc
src/core/lib/gprpp/fork.cc
src/core/lib/gprpp/global_config_env.cc
src/core/lib/gprpp/host_port.cc
src/core/lib/gprpp/mpscq.cc
src/core/lib/gprpp/stat_posix.cc
src/core/lib/gprpp/stat_windows.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/thd_posix.cc
src/core/lib/gprpp/thd_windows.cc
src/core/lib/gprpp/time_util.cc
src/core/lib/profiling/basic_timers.cc
src/core/lib/profiling/stap_timers.cc
test/core/gprpp/single_set_ptr_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(single_set_ptr_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(single_set_ptr_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
absl::base
absl::core_headers
absl::memory
absl::random_random
absl::status
absl::cord
absl::str_format
absl::strings
absl::synchronization
absl::time
absl::optional
upb
)
endif()
if(gRPC_BUILD_TESTS)

@ -7375,6 +7375,104 @@ targets:
- test/core/end2end/cq_verifier.cc
deps:
- grpc_test_util
- name: single_set_ptr_test
gtest: true
build: test
language: c++
headers:
- src/core/ext/upb-generated/google/protobuf/any.upb.h
- src/core/ext/upb-generated/google/rpc/status.upb.h
- src/core/lib/gpr/alloc.h
- src/core/lib/gpr/env.h
- src/core/lib/gpr/murmur_hash.h
- src/core/lib/gpr/spinlock.h
- src/core/lib/gpr/string.h
- src/core/lib/gpr/string_windows.h
- src/core/lib/gpr/time_precise.h
- src/core/lib/gpr/tls.h
- src/core/lib/gpr/tmpfile.h
- src/core/lib/gpr/useful.h
- src/core/lib/gprpp/construct_destruct.h
- src/core/lib/gprpp/debug_location.h
- src/core/lib/gprpp/examine_stack.h
- src/core/lib/gprpp/fork.h
- src/core/lib/gprpp/global_config.h
- src/core/lib/gprpp/global_config_custom.h
- src/core/lib/gprpp/global_config_env.h
- src/core/lib/gprpp/global_config_generic.h
- src/core/lib/gprpp/host_port.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/memory.h
- src/core/lib/gprpp/mpscq.h
- src/core/lib/gprpp/single_set_ptr.h
- src/core/lib/gprpp/stat.h
- src/core/lib/gprpp/status_helper.h
- src/core/lib/gprpp/sync.h
- src/core/lib/gprpp/thd.h
- src/core/lib/gprpp/time_util.h
- src/core/lib/profiling/timers.h
src:
- src/core/ext/upb-generated/google/protobuf/any.upb.c
- src/core/ext/upb-generated/google/rpc/status.upb.c
- src/core/lib/gpr/alloc.cc
- src/core/lib/gpr/atm.cc
- src/core/lib/gpr/cpu_iphone.cc
- src/core/lib/gpr/cpu_linux.cc
- src/core/lib/gpr/cpu_posix.cc
- src/core/lib/gpr/cpu_windows.cc
- src/core/lib/gpr/env_linux.cc
- src/core/lib/gpr/env_posix.cc
- src/core/lib/gpr/env_windows.cc
- src/core/lib/gpr/log.cc
- src/core/lib/gpr/log_android.cc
- src/core/lib/gpr/log_linux.cc
- src/core/lib/gpr/log_posix.cc
- src/core/lib/gpr/log_windows.cc
- src/core/lib/gpr/murmur_hash.cc
- src/core/lib/gpr/string.cc
- src/core/lib/gpr/string_posix.cc
- src/core/lib/gpr/string_util_windows.cc
- src/core/lib/gpr/string_windows.cc
- src/core/lib/gpr/sync.cc
- src/core/lib/gpr/sync_abseil.cc
- src/core/lib/gpr/sync_posix.cc
- src/core/lib/gpr/sync_windows.cc
- src/core/lib/gpr/time.cc
- src/core/lib/gpr/time_posix.cc
- src/core/lib/gpr/time_precise.cc
- src/core/lib/gpr/time_windows.cc
- src/core/lib/gpr/tmpfile_msys.cc
- src/core/lib/gpr/tmpfile_posix.cc
- src/core/lib/gpr/tmpfile_windows.cc
- src/core/lib/gpr/wrap_memcpy.cc
- src/core/lib/gprpp/examine_stack.cc
- src/core/lib/gprpp/fork.cc
- src/core/lib/gprpp/global_config_env.cc
- src/core/lib/gprpp/host_port.cc
- src/core/lib/gprpp/mpscq.cc
- src/core/lib/gprpp/stat_posix.cc
- src/core/lib/gprpp/stat_windows.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/thd_posix.cc
- src/core/lib/gprpp/thd_windows.cc
- src/core/lib/gprpp/time_util.cc
- src/core/lib/profiling/basic_timers.cc
- src/core/lib/profiling/stap_timers.cc
- test/core/gprpp/single_set_ptr_test.cc
deps:
- absl/base:base
- absl/base:core_headers
- absl/memory:memory
- absl/random:random
- absl/status:status
- absl/strings:cord
- absl/strings:str_format
- absl/strings:strings
- absl/synchronization:synchronization
- absl/time:time
- absl/types:optional
- upb
uses_polling: false
- name: sleep_test
gtest: true
build: test

@ -0,0 +1,83 @@
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_CORE_LIB_GPRPP_SINGLE_SET_PTR_H
#define GRPC_CORE_LIB_GPRPP_SINGLE_SET_PTR_H
#include <grpc/support/port_platform.h>
#include <atomic>
#include <memory>
#include <grpc/support/log.h>
namespace grpc_core {
template <class T, class Deleter = std::default_delete<T>>
class SingleSetPtr {
public:
SingleSetPtr() = default;
~SingleSetPtr() { Delete(p_.load(std::memory_order_relaxed)); }
SingleSetPtr(const SingleSetPtr&) = delete;
SingleSetPtr& operator=(const SingleSetPtr&) = delete;
SingleSetPtr(SingleSetPtr&& other) noexcept
: p_(other.p_.exchange(sentinel())) {}
SingleSetPtr& operator=(SingleSetPtr&& other) noexcept {
Set(other.p_.exchange(sentinel(), std::memory_order_acq_rel));
return *this;
}
// Set the pointer;
// if already set, return the pre-set value and delete ptr;
// if deleted, return nullptr and delete ptr.
T* Set(T* ptr) {
T* expected = nullptr;
if (!p_.compare_exchange_strong(expected, ptr, std::memory_order_acq_rel,
std::memory_order_acquire)) {
Delete(ptr);
return expected == sentinel() ? nullptr : expected;
}
return ptr;
}
// Clear the pointer. Cannot be set again.
void Reset() { Delete(p_.exchange(sentinel(), std::memory_order_acq_rel)); }
bool is_set() const {
T* p = p_.load(std::memory_order_acquire);
return p != nullptr && p != sentinel();
}
T* operator->() const {
T* p = p_.load(std::memory_order_acquire);
GPR_DEBUG_ASSERT(p != sentinel());
GPR_DEBUG_ASSERT(p != nullptr);
return p;
}
T& operator*() const { return *operator->(); }
private:
static T* sentinel() { return reinterpret_cast<T*>(1); }
static void Delete(T* p) {
if (p == sentinel() || p == nullptr) return;
Deleter()(p);
}
std::atomic<T*> p_{nullptr};
};
} // namespace grpc_core
#endif // GRPC_CORE_LIB_GPRPP_SINGLE_SET_PTR_H

@ -337,3 +337,15 @@ grpc_cc_test(
"//test/core/util:grpc_suppressions",
],
)
grpc_cc_test(
name = "single_set_ptr_test",
srcs = ["single_set_ptr_test.cc"],
external_deps = ["gtest"],
language = "c++",
uses_polling = False,
deps = [
"//:single_set_ptr",
"//test/core/util:grpc_suppressions",
],
)

@ -0,0 +1,63 @@
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/gprpp/single_set_ptr.h"
#include <thread>
#include <gtest/gtest.h>
namespace grpc_core {
namespace testing {
TEST(SingleSetPtrTest, NoOp) { SingleSetPtr<int>(); }
TEST(SingleSetPtrTest, CanSet) {
SingleSetPtr<int> p;
EXPECT_FALSE(p.is_set());
EXPECT_DEATH_IF_SUPPORTED(gpr_log(GPR_ERROR, "%d", *p), "");
p.Set(new int(42));
EXPECT_EQ(*p, 42);
}
TEST(SingleSetPtrTest, CanReset) {
SingleSetPtr<int> p;
EXPECT_FALSE(p.is_set());
p.Set(new int(42));
EXPECT_TRUE(p.is_set());
p.Set(new int(43));
EXPECT_EQ(*p, 42);
p.Reset();
EXPECT_FALSE(p.is_set());
}
TEST(SingleSetPtrTest, LotsOfSetters) {
SingleSetPtr<int> p;
std::vector<std::thread> threads;
threads.reserve(100);
for (int i = 0; i < 100; i++) {
threads.emplace_back([&p, i]() { p.Set(new int(i)); });
}
for (auto& t : threads) {
t.join();
}
}
} // namespace testing
} // namespace grpc_core
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -6471,6 +6471,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "single_set_ptr_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save