C++程序  |  103行  |  3.42 KB

/*
 * 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<std::mutex> 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<Info>();
    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<std::mutex> 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<std::mutex> 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<std::mutex> lock(mStateMutex);
    mState = State::Stopped;
}