blob: 3c51ff0834034e6d0c34ebfca92fcf4a7ed86eb5 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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 DATASTAX_INTERNAL_LOOP_WATCHER_HPP
#define DATASTAX_INTERNAL_LOOP_WATCHER_HPP
#include "allocated.hpp"
#include "callback.hpp"
#include "macros.hpp"
#include <uv.h>
namespace datastax { namespace internal { namespace core {
template <class Type, class HType>
class LoopWatcher {
public:
typedef internal::Callback<void, Type*> Callback;
typedef HType HandleType;
LoopWatcher()
: handle_(NULL)
, state_(CLOSED) {}
~LoopWatcher() { close_handle(); }
/**
* Start the handle.
*
* @param loop The event loop that will process the handle.
* @param callback A callback that handles events.
*/
int start(uv_loop_t* loop, const Callback& callback) {
int rc = 0;
if (handle_ == NULL) {
handle_ = new AllocatedT<HandleType>();
handle_->loop = NULL;
handle_->data = this;
}
if (state_ == CLOSED) {
rc = Type::init_handle(loop, handle_);
if (rc != 0) return rc;
state_ = STOPPED;
}
if (state_ == STOPPED) {
rc = Type::start_handle(handle_, on_run);
if (rc != 0) return rc;
state_ = STARTED;
}
callback_ = callback;
return 0;
}
/**
* Stop the handle.
*/
void stop() {
if (state_ == STARTED) {
state_ = STOPPED;
Type::stop_handle(handle_);
}
}
/**
* Close the handle.
*/
void close_handle() {
if (handle_ != NULL) {
if (state_ == CLOSED) { // The handle was allocated, but initialization failed.
delete handle_;
} else { // If initialized or started then close the handle properly.
uv_close(reinterpret_cast<uv_handle_t*>(handle_), on_close);
}
state_ = CLOSED;
handle_ = NULL;
}
}
public:
bool is_running() const { return state_ == STARTED; }
uv_loop_t* loop() { return handle_ ? handle_->loop : NULL; }
private:
static void on_run(HandleType* handle) {
Type* watcher = static_cast<Type*>(handle->data);
watcher->callback_(watcher);
}
static void on_close(uv_handle_t* handle) {
delete reinterpret_cast<AllocatedT<HandleType>*>(handle);
}
private:
enum State { CLOSED, STOPPED, STARTED };
private:
AllocatedT<HandleType>* handle_;
State state_;
Callback callback_;
private:
DISALLOW_COPY_AND_ASSIGN(LoopWatcher);
};
/**
* A wrapper for uv_prepare. This is useful for running a callback right before
* the event loop begins polling.
*/
class Prepare : public LoopWatcher<Prepare, uv_prepare_t> {
private:
typedef uv_prepare_cb HandleCallback;
friend class LoopWatcher<Prepare, HandleType>;
static int init_handle(uv_loop_t* loop, HandleType* handle) {
return uv_prepare_init(loop, handle);
}
static int start_handle(HandleType* handle, HandleCallback callback) {
return uv_prepare_start(handle, callback);
}
static void stop_handle(HandleType* handle) { uv_prepare_stop(handle); }
};
/**
* A wrapper for uv_check. This is useful for running a callback right after
* the event loop returns from polling.
*/
class Check : public LoopWatcher<Check, uv_check_t> {
private:
typedef uv_check_cb HandleCallback;
friend class LoopWatcher<Check, HandleType>;
static int init_handle(uv_loop_t* loop, HandleType* handle) {
return uv_check_init(loop, handle);
}
static int start_handle(HandleType* handle, HandleCallback callback) {
return uv_check_start(handle, callback);
}
static void stop_handle(HandleType* handle) { uv_check_stop(handle); }
};
}}} // namespace datastax::internal::core
#endif