Add Apple implementation for timer

PiperOrigin-RevId: 511201457
This commit is contained in:
Nick Bourdakos
2023-02-21 08:03:09 -08:00
committed by Copybara-Service
parent a977a6bd7c
commit b59ed0b70f
3 changed files with 67 additions and 5 deletions
@@ -224,7 +224,6 @@ absl::StatusOr<WebResponse> ImplementationPlatform::SendRequest(const WebRequest
return webResponse;
}
// TODO(b/261511529): Add implementation.
std::unique_ptr<Timer> ImplementationPlatform::CreateTimer() {
return std::make_unique<apple::Timer>();
}
@@ -15,6 +15,8 @@
#ifndef PLATFORM_IMPL_APPLE_TIMER_H_
#define PLATFORM_IMPL_APPLE_TIMER_H_
#import <Foundation/Foundation.h>
#include <utility>
#include "internal/platform/implementation/timer.h"
@@ -25,7 +27,7 @@ namespace apple {
class Timer : public api::Timer {
public:
Timer() = default;
~Timer() override = default;
~Timer() override;
bool Create(int delay, int interval,
absl::AnyInvocable<void()> callback) override;
@@ -33,6 +35,10 @@ class Timer : public api::Timer {
bool Stop() override;
bool FireNow() override;
private:
absl::AnyInvocable<void()> callback_;
dispatch_source_t timer_;
};
} // namespace apple
@@ -17,15 +17,72 @@
#include <utility>
#include "internal/platform/implementation/timer.h"
#import "GoogleToolboxForMac/GTMLogger.h"
// The leeway parameter is a hint from the application as to the amount of time, in nanoseconds, up
// to which the system can defer the timer to align with other system activity for improved system
// performance or power consumption. For example, an application might perform a periodic task every
// 5 minutes, with a leeway of up to 30 seconds. Note that some latency is to be expected for all
// timers, even when a leeway value of zero is specified.
uint64_t const GNCTimerLeewayInNanoseconds = 0;
namespace nearby {
namespace apple {
bool Timer::Create(int delay, int interval, absl::AnyInvocable<void()> callback) { return true; }
Timer::~Timer() { Stop(); }
bool Timer::Stop() { return true; }
bool Timer::Create(int delay, int interval, absl::AnyInvocable<void()> callback) {
if (delay < 0 || interval < 0) {
GTMLoggerError(@"Delay and interval must be positive or zero.");
return false;
}
bool Timer::FireNow() { return true; }
if (timer_ != nil) {
GTMLoggerError(@"Timer has already started.");
return false;
}
uint64_t delayInNanoseconds = delay * NSEC_PER_MSEC;
// If `interval` is 0, it means we only want the timer to fire once. We map this to
// `DISPATCH_TIME_FOREVER` to have this effect.
uint64_t intervalInNanoseconds = interval == 0 ? DISPATCH_TIME_FOREVER : interval * NSEC_PER_MSEC;
callback_ = std::move(callback);
timer_ = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, /*handle=*/0, /*mask=*/0,
dispatch_get_main_queue());
dispatch_source_set_event_handler(timer_, ^{
if (callback_ != nil) {
callback_();
}
// If our interval is `DISPATCH_TIME_FOREVER`, it means we only want the timer to fire once.
if (intervalInNanoseconds == DISPATCH_TIME_FOREVER) {
Stop();
}
});
dispatch_source_set_timer(timer_, dispatch_time(DISPATCH_TIME_NOW, delayInNanoseconds),
intervalInNanoseconds, GNCTimerLeewayInNanoseconds);
dispatch_resume(timer_);
return true;
}
bool Timer::Stop() {
if (timer_ != nil) {
dispatch_source_cancel(timer_);
}
timer_ = nil;
callback_ = nil;
return true;
}
bool Timer::FireNow() {
if (callback_ != nil) {
callback_();
return true;
}
return false;
}
} // namespace apple
} // namespace nearby