Introduce and use uv::timer

This commit is contained in:
John Firebaugh
2015-04-30 12:28:29 -04:00
parent 95214472d4
commit 64251eec75
2 changed files with 64 additions and 34 deletions

View File

@@ -58,14 +58,11 @@ public:
void retry() override;
private:
void cancelTimer();
void start();
void handleResult(NSData *data, NSURLResponse *res, NSError *error);
void handleResponse();
void retry(uint64_t timeout);
static void restart(uv_timer_t *timer, int);
HTTPNSURLContext *context = nullptr;
bool cancelled = false;
NSURLSessionDataTask *task = nullptr;
@@ -73,8 +70,8 @@ private:
const std::shared_ptr<const Response> existingResponse;
ResponseStatus status = ResponseStatus::PermanentError;
uv::async async;
uv::timer timer;
int attempts = 0;
uv_timer_t *timer = nullptr;
enum : bool { PreemptImmediately, ExponentialBackoff } strategy = PreemptImmediately;
static const int maxAttempts = 4;
@@ -134,7 +131,8 @@ HTTPRequest::HTTPRequest(HTTPNSURLContext* context_, const Resource& resource_,
: RequestBase(resource_, callback_),
context(context_),
existingResponse(existingResponse_),
async(loop, [this] { handleResponse(); }) {
async(loop, [this] { handleResponse(); }),
timer(loop) {
context->addRequest(this);
start();
}
@@ -143,7 +141,7 @@ HTTPRequest::~HTTPRequest() {
assert(!task);
// Stop the backoff timer to avoid re-triggering this request.
cancelTimer();
timer.stop();
context->removeRequest(this);
}
@@ -220,7 +218,7 @@ void HTTPRequest::cancel() {
cancelled = true;
// Stop the backoff timer to avoid re-triggering this request.
cancelTimer();
timer.stop();
if (task) {
[task cancel];
@@ -231,14 +229,6 @@ void HTTPRequest::cancel() {
}
}
void HTTPRequest::cancelTimer() {
if (timer) {
uv_timer_stop(timer);
uv::close(timer);
timer = nullptr;
}
}
int64_t parseCacheControl(const char *value) {
if (value) {
unsigned long long seconds = 0;
@@ -360,34 +350,20 @@ void HTTPRequest::handleResult(NSData *data, NSURLResponse *res, NSError *error)
void HTTPRequest::retry(uint64_t timeout) {
response.reset();
assert(!timer);
timer = new uv_timer_t;
timer->data = this;
uv_timer_init(async.get()->loop, timer);
uv_timer_start(timer, restart, timeout, 0);
timer.stop();
timer.start(timeout, 0, [this] { start(); });
}
void HTTPRequest::retry() {
// All batons get notified when the network status changed, but some of them
// might not actually wait for the network to become available again.
if (timer && strategy == PreemptImmediately) {
if (strategy == PreemptImmediately) {
// Triggers the timer upon the next event loop iteration.
uv_timer_stop(timer);
uv_timer_start(timer, restart, 0, 0);
timer.stop();
timer.start(0, 0, [this] { start(); });
}
}
void HTTPRequest::restart(uv_timer_t *timer, int) {
// Restart the request.
auto impl = reinterpret_cast<HTTPRequest *>(timer->data);
// Get rid of the timer.
impl->timer = nullptr;
uv::close(timer);
impl->start();
}
std::unique_ptr<HTTPContext> HTTPContext::createContext(uv_loop_t* loop) {
return util::make_unique<HTTPNSURLContext>(loop);
}

View File

@@ -121,6 +121,60 @@ private:
std::function<void ()> fn;
};
class timer : public mbgl::util::noncopyable {
public:
inline timer(uv_loop_t* loop)
: t(new uv_timer_t)
{
t->data = this;
if (uv_timer_init(loop, t.get()) != 0) {
throw std::runtime_error("failed to initialize timer");
}
}
inline timer() {
close(std::move(t));
}
inline void start(uint64_t timeout, uint64_t repeat, std::function<void ()> fn_) {
fn = fn_;
if (uv_timer_start(t.get(), timer_cb, timeout, repeat) != 0) {
throw std::runtime_error("failed to start timer");
}
}
inline void stop() {
fn = nullptr;
if (uv_timer_stop(t.get()) != 0) {
throw std::runtime_error("failed to stop timer");
}
}
inline void ref() {
uv_ref(reinterpret_cast<uv_handle_t*>(t.get()));
}
inline void unref() {
uv_unref(reinterpret_cast<uv_handle_t*>(t.get()));
}
inline uv_timer_t* get() {
return t.get();
}
private:
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
static void timer_cb(uv_timer_t* t, int) {
#else
static void timer_cb(uv_timer_t* t) {
#endif
reinterpret_cast<timer*>(t->data)->fn();
}
std::unique_ptr<uv_timer_t> t;
std::function<void ()> fn;
};
class mutex : public mbgl::util::noncopyable {
public:
inline mutex() {