From 64251eec75dd4cd9ec6aacc1c1e7ecc379b8ad9e Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 30 Apr 2015 12:28:29 -0400 Subject: [PATCH] Introduce and use uv::timer --- platform/darwin/http_request_nsurl.mm | 44 +++++----------------- src/mbgl/util/uv_detail.hpp | 54 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/platform/darwin/http_request_nsurl.mm b/platform/darwin/http_request_nsurl.mm index 9572970f2..509e158af 100644 --- a/platform/darwin/http_request_nsurl.mm +++ b/platform/darwin/http_request_nsurl.mm @@ -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 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(timer->data); - - // Get rid of the timer. - impl->timer = nullptr; - uv::close(timer); - - impl->start(); -} - std::unique_ptr HTTPContext::createContext(uv_loop_t* loop) { return util::make_unique(loop); } diff --git a/src/mbgl/util/uv_detail.hpp b/src/mbgl/util/uv_detail.hpp index fbc0ec5aa..f77bec0fa 100644 --- a/src/mbgl/util/uv_detail.hpp +++ b/src/mbgl/util/uv_detail.hpp @@ -121,6 +121,60 @@ private: std::function 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 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(t.get())); + } + + inline void unref() { + uv_unref(reinterpret_cast(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(t->data)->fn(); + } + + std::unique_ptr t; + std::function fn; +}; + class mutex : public mbgl::util::noncopyable { public: inline mutex() {