/* * Copyright (C) 2017 The Android Open Source Project * * 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 "halstate.h" HalState::HalState() : mState(State::Constructed) { } bool HalState::init() { // Ensure that checking the state and waiting on the condition is atomic. std::unique_lock lock(mStateMutex); if (mState != State::Stopped && mState != State::Constructed) { // We can only initialize when freshly constructed or stopped return false; } if (mInfo) { // We are in the correct state but our info object is still allocated. // This is a logic error somewhere and should not happen. return false; } auto info = std::make_unique(); if (info->init()) { // Only store the info object to keep it alive if init succeeded. // Otherwise we're going to remain in the previous state and having an // uninitialized info object around will cause inconsistency. mInfo = std::move(info); mState = State::Initialized; return true; } // If we failed to initalize we remain in the same state. return false; } bool HalState::stop(StopHandler stopHandler) { { // Ensure atomicity in checking and setting state std::unique_lock lock(mStateMutex); if (mState == State::Stopping || mState == State::Stopped) { // Already stopping or stopped, nothing to do return false; } if (mState != State::Running) { // Make sure there is no info object anymore. It should never exist // in the stopped state. mInfo.reset(); // If we're neither stopping, stopped nor running then we can't stop // again. It seems that sometimes the client expects to be able to // call this when initialized or constructed so we'll set the state // to stopped. We have to return false to prevent the caller from // waiting for the callback though. Calling the callback here from // the same thread that called stop could cause a deadlock. mState = State::Stopped; return false; } mState = State::Stopping; } mInfo->stop(std::bind(&HalState::onStop, this, stopHandler)); // We have now requested the stop, we'll change state in the stop handler // when it's called. return true; } bool HalState::eventLoop() { { // Atomically check and set state to running std::unique_lock lock(mStateMutex); if (mState != State::Initialized || !mInfo) { return false; } mState = State::Running; } mInfo->eventLoop(); return true; } Info* HalState::info() { return mInfo.get(); } void HalState::onStop(StopHandler stopHandler) { stopHandler(); mInfo.reset(); std::unique_lock lock(mStateMutex); mState = State::Stopped; }