From e48949f0b44d0f8755cbbc3837a2b591867cd0bf Mon Sep 17 00:00:00 2001
From: David Garcia Quintas <dgq@google.com>
Date: Mon, 19 Jun 2017 13:57:32 -0700
Subject: [PATCH] Make grpc::Alarm non-copyable

---
 include/grpc++/alarm.h            | 21 +++++++++++++++++++--
 test/cpp/common/alarm_cpp_test.cc | 19 +++++++++++++++++++
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/include/grpc++/alarm.h b/include/grpc++/alarm.h
index bd000cf4f7..ed8dacbc94 100644
--- a/include/grpc++/alarm.h
+++ b/include/grpc++/alarm.h
@@ -52,8 +52,25 @@ class Alarm : private GrpcLibraryCodegen {
         alarm_(grpc_alarm_create(cq->cq(), TimePoint<T>(deadline).raw_time(),
                                  static_cast<void*>(&tag_))) {}
 
+  /// Alarms aren't copyable.
+  Alarm(const Alarm&) = delete;
+  Alarm& operator=(const Alarm&) = delete;
+
+  /// Alarms are movable.
+  Alarm(Alarm&& rhs) : tag_(rhs.tag_), alarm_(rhs.alarm_) {
+    rhs.alarm_ = nullptr;
+  }
+  Alarm& operator=(Alarm&& rhs) {
+    tag_ = rhs.tag_;
+    alarm_ = rhs.alarm_;
+    rhs.alarm_ = nullptr;
+    return *this;
+  }
+
   /// Destroy the given completion queue alarm, cancelling it in the process.
-  ~Alarm() { grpc_alarm_destroy(alarm_); }
+  ~Alarm() {
+    if (alarm_ != nullptr) grpc_alarm_destroy(alarm_);
+  }
 
   /// Cancel a completion queue alarm. Calling this function over an alarm that
   /// has already fired has no effect.
@@ -73,7 +90,7 @@ class Alarm : private GrpcLibraryCodegen {
   };
 
   AlarmEntry tag_;
-  grpc_alarm* const alarm_;  // owned
+  grpc_alarm* alarm_;  // owned
 };
 
 }  // namespace grpc
diff --git a/test/cpp/common/alarm_cpp_test.cc b/test/cpp/common/alarm_cpp_test.cc
index 3e4999994a..760dd7b956 100644
--- a/test/cpp/common/alarm_cpp_test.cc
+++ b/test/cpp/common/alarm_cpp_test.cc
@@ -40,6 +40,25 @@ TEST(AlarmTest, RegularExpiry) {
   EXPECT_EQ(junk, output_tag);
 }
 
+TEST(AlarmTest, Move) {
+  CompletionQueue cq;
+  void* junk = reinterpret_cast<void*>(1618033);
+  Alarm first(&cq, grpc_timeout_seconds_to_deadline(1), junk);
+  // Move constructor.
+  Alarm second(std::move(first));
+  // Moving assignment.
+  first = std::move(second);
+
+  void* output_tag;
+  bool ok;
+  const CompletionQueue::NextStatus status = cq.AsyncNext(
+      (void**)&output_tag, &ok, grpc_timeout_seconds_to_deadline(2));
+
+  EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
+  EXPECT_TRUE(ok);
+  EXPECT_EQ(junk, output_tag);
+}
+
 TEST(AlarmTest, RegularExpiryChrono) {
   CompletionQueue cq;
   void* junk = reinterpret_cast<void*>(1618033);
-- 
GitLab