1 /* 2 Copyright (c) DataStax, Inc. 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 #ifndef DATASTAX_INTERNAL_LOOP_WATCHER_HPP 18 #define DATASTAX_INTERNAL_LOOP_WATCHER_HPP 19 20 #include "allocated.hpp" 21 #include "callback.hpp" 22 #include "macros.hpp" 23 24 #include <uv.h> 25 26 namespace datastax { namespace internal { namespace core { 27 28 template <class Type, class HType> 29 class LoopWatcher { 30 public: 31 typedef internal::Callback<void, Type*> Callback; 32 typedef HType HandleType; 33 LoopWatcher()34 LoopWatcher() 35 : handle_(NULL) 36 , state_(CLOSED) {} 37 ~LoopWatcher()38 ~LoopWatcher() { close_handle(); } 39 40 /** 41 * Start the handle. 42 * 43 * @param loop The event loop that will process the handle. 44 * @param callback A callback that handles events. 45 */ start(uv_loop_t * loop,const Callback & callback)46 int start(uv_loop_t* loop, const Callback& callback) { 47 int rc = 0; 48 if (handle_ == NULL) { 49 handle_ = new AllocatedT<HandleType>(); 50 handle_->loop = NULL; 51 handle_->data = this; 52 } 53 if (state_ == CLOSED) { 54 rc = Type::init_handle(loop, handle_); 55 if (rc != 0) return rc; 56 state_ = STOPPED; 57 } 58 if (state_ == STOPPED) { 59 rc = Type::start_handle(handle_, on_run); 60 if (rc != 0) return rc; 61 state_ = STARTED; 62 } 63 callback_ = callback; 64 return 0; 65 } 66 67 /** 68 * Stop the handle. 69 */ stop()70 void stop() { 71 if (state_ == STARTED) { 72 state_ = STOPPED; 73 Type::stop_handle(handle_); 74 } 75 } 76 77 /** 78 * Close the handle. 79 */ close_handle()80 void close_handle() { 81 if (handle_ != NULL) { 82 if (state_ == CLOSED) { // The handle was allocated, but initialization failed. 83 delete handle_; 84 } else { // If initialized or started then close the handle properly. 85 uv_close(reinterpret_cast<uv_handle_t*>(handle_), on_close); 86 } 87 state_ = CLOSED; 88 handle_ = NULL; 89 } 90 } 91 92 public: is_running() const93 bool is_running() const { return state_ == STARTED; } loop()94 uv_loop_t* loop() { return handle_ ? handle_->loop : NULL; } 95 96 private: on_run(HandleType * handle)97 static void on_run(HandleType* handle) { 98 Type* watcher = static_cast<Type*>(handle->data); 99 watcher->callback_(watcher); 100 } 101 on_close(uv_handle_t * handle)102 static void on_close(uv_handle_t* handle) { 103 delete reinterpret_cast<AllocatedT<HandleType>*>(handle); 104 } 105 106 private: 107 enum State { CLOSED, STOPPED, STARTED }; 108 109 private: 110 AllocatedT<HandleType>* handle_; 111 State state_; 112 Callback callback_; 113 114 private: 115 DISALLOW_COPY_AND_ASSIGN(LoopWatcher); 116 }; 117 118 /** 119 * A wrapper for uv_prepare. This is useful for running a callback right before 120 * the event loop begins polling. 121 */ 122 class Prepare : public LoopWatcher<Prepare, uv_prepare_t> { 123 private: 124 typedef uv_prepare_cb HandleCallback; 125 friend class LoopWatcher<Prepare, HandleType>; 126 init_handle(uv_loop_t * loop,HandleType * handle)127 static int init_handle(uv_loop_t* loop, HandleType* handle) { 128 return uv_prepare_init(loop, handle); 129 } 130 start_handle(HandleType * handle,HandleCallback callback)131 static int start_handle(HandleType* handle, HandleCallback callback) { 132 return uv_prepare_start(handle, callback); 133 } 134 stop_handle(HandleType * handle)135 static void stop_handle(HandleType* handle) { uv_prepare_stop(handle); } 136 }; 137 138 /** 139 * A wrapper for uv_check. This is useful for running a callback right after 140 * the event loop returns from polling. 141 */ 142 class Check : public LoopWatcher<Check, uv_check_t> { 143 private: 144 typedef uv_check_cb HandleCallback; 145 friend class LoopWatcher<Check, HandleType>; 146 init_handle(uv_loop_t * loop,HandleType * handle)147 static int init_handle(uv_loop_t* loop, HandleType* handle) { 148 return uv_check_init(loop, handle); 149 } 150 start_handle(HandleType * handle,HandleCallback callback)151 static int start_handle(HandleType* handle, HandleCallback callback) { 152 return uv_check_start(handle, callback); 153 } 154 stop_handle(HandleType * handle)155 static void stop_handle(HandleType* handle) { uv_check_stop(handle); } 156 }; 157 158 }}} // namespace datastax::internal::core 159 160 #endif 161