alarm.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /*
  2. * Copyright 2018 gRPC authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. #include <grpcpp/alarm.h>
  18. #include <memory>
  19. #include <grpc/support/log.h>
  20. #include <grpc/support/port_platform.h>
  21. #include <grpcpp/completion_queue.h>
  22. #include <grpcpp/impl/grpc_library.h>
  23. #include <grpcpp/support/time.h>
  24. #include "src/core/lib/iomgr/exec_ctx.h"
  25. #include "src/core/lib/iomgr/executor.h"
  26. #include "src/core/lib/iomgr/timer.h"
  27. #include "src/core/lib/surface/completion_queue.h"
  28. #include <grpc/support/log.h>
  29. #include "src/core/lib/debug/trace.h"
  30. namespace grpc_impl {
  31. namespace internal {
  32. class AlarmImpl : public ::grpc::internal::CompletionQueueTag {
  33. public:
  34. AlarmImpl() : cq_(nullptr), tag_(nullptr) {
  35. gpr_ref_init(&refs_, 1);
  36. grpc_timer_init_unset(&timer_);
  37. }
  38. ~AlarmImpl() {}
  39. bool FinalizeResult(void** tag, bool* /*status*/) override {
  40. *tag = tag_;
  41. Unref();
  42. return true;
  43. }
  44. void Set(::grpc::CompletionQueue* cq, gpr_timespec deadline, void* tag) {
  45. grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
  46. grpc_core::ExecCtx exec_ctx;
  47. GRPC_CQ_INTERNAL_REF(cq->cq(), "alarm");
  48. cq_ = cq->cq();
  49. tag_ = tag;
  50. GPR_ASSERT(grpc_cq_begin_op(cq_, this));
  51. GRPC_CLOSURE_INIT(
  52. &on_alarm_,
  53. [](void* arg, grpc_error* error) {
  54. // queue the op on the completion queue
  55. AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
  56. alarm->Ref();
  57. // Preserve the cq and reset the cq_ so that the alarm
  58. // can be reset when the alarm tag is delivered.
  59. grpc_completion_queue* cq = alarm->cq_;
  60. alarm->cq_ = nullptr;
  61. grpc_cq_end_op(
  62. cq, alarm, error,
  63. [](void* /*arg*/, grpc_cq_completion* /*completion*/) {}, arg,
  64. &alarm->completion_);
  65. GRPC_CQ_INTERNAL_UNREF(cq, "alarm");
  66. },
  67. this, grpc_schedule_on_exec_ctx);
  68. grpc_timer_init(&timer_, grpc_timespec_to_millis_round_up(deadline),
  69. &on_alarm_);
  70. }
  71. void Set(gpr_timespec deadline, std::function<void(bool)> f) {
  72. grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
  73. grpc_core::ExecCtx exec_ctx;
  74. // Don't use any CQ at all. Instead just use the timer to fire the function
  75. callback_ = std::move(f);
  76. Ref();
  77. GRPC_CLOSURE_INIT(&on_alarm_,
  78. [](void* arg, grpc_error* error) {
  79. grpc_core::Executor::Run(
  80. GRPC_CLOSURE_CREATE(
  81. [](void* arg, grpc_error* error) {
  82. AlarmImpl* alarm =
  83. static_cast<AlarmImpl*>(arg);
  84. alarm->callback_(error == GRPC_ERROR_NONE);
  85. alarm->Unref();
  86. },
  87. arg, nullptr),
  88. error);
  89. },
  90. this, grpc_schedule_on_exec_ctx);
  91. grpc_timer_init(&timer_, grpc_timespec_to_millis_round_up(deadline),
  92. &on_alarm_);
  93. }
  94. void Cancel() {
  95. grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
  96. grpc_core::ExecCtx exec_ctx;
  97. grpc_timer_cancel(&timer_);
  98. }
  99. void Destroy() {
  100. Cancel();
  101. Unref();
  102. }
  103. private:
  104. void Ref() { gpr_ref(&refs_); }
  105. void Unref() {
  106. if (gpr_unref(&refs_)) {
  107. delete this;
  108. }
  109. }
  110. grpc_timer timer_;
  111. gpr_refcount refs_;
  112. grpc_closure on_alarm_;
  113. grpc_cq_completion completion_;
  114. // completion queue where events about this alarm will be posted
  115. grpc_completion_queue* cq_;
  116. void* tag_;
  117. std::function<void(bool)> callback_;
  118. };
  119. } // namespace internal
  120. static ::grpc::internal::GrpcLibraryInitializer g_gli_initializer;
  121. Alarm::Alarm() : alarm_(new internal::AlarmImpl()) {
  122. g_gli_initializer.summon();
  123. }
  124. void Alarm::SetInternal(::grpc::CompletionQueue* cq, gpr_timespec deadline,
  125. void* tag) {
  126. // Note that we know that alarm_ is actually an internal::AlarmImpl
  127. // but we declared it as the base pointer to avoid a forward declaration
  128. // or exposing core data structures in the C++ public headers.
  129. // Thus it is safe to use a static_cast to the subclass here, and the
  130. // C++ style guide allows us to do so in this case
  131. static_cast<internal::AlarmImpl*>(alarm_)->Set(cq, deadline, tag);
  132. }
  133. void Alarm::SetInternal(gpr_timespec deadline, std::function<void(bool)> f) {
  134. // Note that we know that alarm_ is actually an internal::AlarmImpl
  135. // but we declared it as the base pointer to avoid a forward declaration
  136. // or exposing core data structures in the C++ public headers.
  137. // Thus it is safe to use a static_cast to the subclass here, and the
  138. // C++ style guide allows us to do so in this case
  139. static_cast<internal::AlarmImpl*>(alarm_)->Set(deadline, std::move(f));
  140. }
  141. Alarm::~Alarm() {
  142. if (alarm_ != nullptr) {
  143. static_cast<internal::AlarmImpl*>(alarm_)->Destroy();
  144. }
  145. }
  146. void Alarm::Cancel() { static_cast<internal::AlarmImpl*>(alarm_)->Cancel(); }
  147. } // namespace grpc_impl