| /** |
| 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. |
| */ |
| |
| /** |
| * @file AsyncTimer.cc |
| */ |
| #include "atscppapi/AsyncTimer.h" |
| #include <ts/ts.h> |
| #include "logging_internal.h" |
| |
| using namespace atscppapi; |
| |
| struct atscppapi::AsyncTimerState { |
| TSCont cont_; |
| AsyncTimer::Type type_; |
| int period_in_ms_; |
| int initial_period_in_ms_; |
| TSAction initial_timer_action_; |
| TSAction periodic_timer_action_; |
| AsyncTimer *timer_; |
| shared_ptr<AsyncDispatchControllerBase> dispatch_controller_; |
| AsyncTimerState(AsyncTimer::Type type, int period_in_ms, int initial_period_in_ms, AsyncTimer *timer) |
| : type_(type), period_in_ms_(period_in_ms), initial_period_in_ms_(initial_period_in_ms), |
| initial_timer_action_(NULL), periodic_timer_action_(NULL), timer_(timer) { } |
| }; |
| |
| namespace { |
| |
| int handleTimerEvent(TSCont cont, TSEvent event, void *edata) { |
| AsyncTimerState *state = static_cast<AsyncTimerState *>(TSContDataGet(cont)); |
| if (state->initial_timer_action_) { |
| LOG_DEBUG("Received initial timer event."); |
| state->initial_timer_action_ = NULL; // mark it so that it won't be canceled in the destructor |
| if (state->type_ == AsyncTimer::TYPE_PERIODIC) { |
| LOG_DEBUG("Scheduling periodic event now"); |
| state->periodic_timer_action_ = TSContScheduleEvery(state->cont_, state->period_in_ms_, |
| TS_THREAD_POOL_DEFAULT); |
| } |
| } |
| if (!state->dispatch_controller_->dispatch()) { |
| LOG_DEBUG("Receiver has died. Destroying timer"); |
| delete state->timer_; // auto-destruct only in this case |
| } |
| return 0; |
| } |
| |
| } |
| |
| AsyncTimer::AsyncTimer(Type type, int period_in_ms, int initial_period_in_ms) { |
| state_ = new AsyncTimerState(type, period_in_ms, initial_period_in_ms, this); |
| state_->cont_ = TSContCreate(handleTimerEvent, TSMutexCreate()); |
| TSContDataSet(state_->cont_, static_cast<void *>(state_)); |
| } |
| |
| void AsyncTimer::run(shared_ptr<AsyncDispatchControllerBase> dispatch_controller) { |
| int one_off_timeout_in_ms = 0; |
| int regular_timeout_in_ms = 0; |
| if (state_->type_ == AsyncTimer::TYPE_ONE_OFF) { |
| one_off_timeout_in_ms = state_->period_in_ms_; |
| } |
| else { |
| one_off_timeout_in_ms = state_->initial_period_in_ms_; |
| regular_timeout_in_ms = state_->period_in_ms_; |
| } |
| if (one_off_timeout_in_ms) { |
| LOG_DEBUG("Scheduling initial/one-off event"); |
| state_->initial_timer_action_ = TSContSchedule(state_->cont_, one_off_timeout_in_ms, |
| TS_THREAD_POOL_DEFAULT); |
| } |
| else if (regular_timeout_in_ms) { |
| LOG_DEBUG("Scheduling regular timer events"); |
| state_->periodic_timer_action_ = TSContScheduleEvery(state_->cont_, regular_timeout_in_ms, |
| TS_THREAD_POOL_DEFAULT); |
| } |
| state_->dispatch_controller_ = dispatch_controller; |
| } |
| |
| AsyncTimer::~AsyncTimer() { |
| TSMutexLock(TSContMutexGet(state_->cont_)); |
| if (state_->initial_timer_action_) { |
| LOG_DEBUG("Canceling initial timer action"); |
| TSActionCancel(state_->initial_timer_action_); |
| } |
| if (state_->periodic_timer_action_) { |
| LOG_DEBUG("Canceling periodic timer action"); |
| TSActionCancel(state_->periodic_timer_action_); |
| } |
| LOG_DEBUG("Destroying cont"); |
| TSContDestroy(state_->cont_); |
| delete state_; |
| } |