blob: 9750590fb20f1b80c92df1129718a581cc985373 [file] [log] [blame]
/*
Copyright 2014 Google Inc.
Licensed 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.
*/
#include <time.h>
#include "common/scheduler.h"
#include "base/logging.h"
namespace ime_goopy {
Scheduler::Scheduler() : running_(false) {
}
Scheduler::~Scheduler() {
}
void Scheduler::AddJob(uint32 default_interval,
uint32 max_interval,
uint32 delay_start,
JobCallback* callback) {
assert(default_interval);
assert(max_interval);
assert(callback);
assert(!running_);
JobInfo* info = new JobInfo;
ZeroMemory(info, sizeof(*info));
info->default_interval = default_interval;
info->max_interval = max_interval;
info->delay_start = delay_start;
info->callback = callback;
jobs_.push_back(info);
}
bool Scheduler::Start() {
assert(!running_);
srand(static_cast<unsigned int>(time(NULL)));
running_ = true;
bool all_success = true;
for (int i = 0; i < jobs_.size(); i++) {
uint32 delay = 0;
if (jobs_[i]->delay_start)
delay = MulDiv(rand(), jobs_[i]->delay_start, RAND_MAX);
jobs_[i]->timer = CreateTimer(jobs_[i], delay, jobs_[i]->default_interval);
if (!jobs_[i]->timer) all_success = false;
}
return all_success;
}
void Scheduler::Stop() {
assert(running_);
running_ = false;
for (int i = 0; i < jobs_.size(); i++) {
if (!jobs_[i]->timer) continue;
DeleteTimer(jobs_[i]->timer);
jobs_[i]->timer = NULL;
jobs_[i]->skip_count = 0;
jobs_[i]->backoff_count = 0;
delete jobs_[i]->callback;
delete jobs_[i];
}
jobs_.clear();
}
void Scheduler::TimerCallback(void* param, BOOLEAN timer_or_wait) {
assert(param);
JobInfo* job = reinterpret_cast<JobInfo*>(param);
if (job->running) return;
if (job->skip_count) {
job->skip_count--;
DLOG(INFO) << "Backoff, " << job->skip_count << " times left...";
return;
}
job->running = true;
CoInitialize(NULL);
bool success = job->callback->Run();
CoUninitialize();
job->running = false;
if (success) {
job->backoff_count = 0;
} else {
uint32 new_backoff_count =
(job->backoff_count == 0) ? 1 : job->backoff_count * 2;
if (new_backoff_count * job->default_interval < job->max_interval)
job->backoff_count = new_backoff_count;
job->skip_count = job->backoff_count;
}
// Reduce memory usage.
SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
}
HANDLE Scheduler::CreateTimer(JobInfo* job_info, DWORD due_time, DWORD period) {
HANDLE new_timer = NULL;
bool success = CreateTimerQueueTimer(&new_timer,
NULL,
&Scheduler::TimerCallback,
reinterpret_cast<void*>(job_info),
due_time * 1000,
period * 1000,
WT_EXECUTELONGFUNCTION);
if (!success) return NULL;
return new_timer;
}
void Scheduler::DeleteTimer(HANDLE timer) {
// Wait for the callback to complete before return.
DeleteTimerQueueTimer(NULL, timer, INVALID_HANDLE_VALUE);
}
} // namespace ime_sync