1e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong/*
2e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong * Copyright (C) 2016 The Android Open Source Project
3e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong *
4e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong * Licensed under the Apache License, Version 2.0 (the "License");
5e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong * you may not use this file except in compliance with the License.
6e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong * You may obtain a copy of the License at
7e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong *
8e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong *      http://www.apache.org/licenses/LICENSE-2.0
9e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong *
10e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong * Unless required by applicable law or agreed to in writing, software
11e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong * distributed under the License is distributed on an "AS IS" BASIS,
12e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong * See the License for the specific language governing permissions and
14e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong * limitations under the License.
15e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong */
16e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong
17e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong#include <condition_variable>
18e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong#include <chrono>
19e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong#include <functional>
20e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong#include <mutex>
21e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong#include <thread>
22e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong
23e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong#include <hidl/Status.h>
24e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong
25e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hongnamespace android {
26e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hongnamespace lshal {
27e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong
28e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hongstatic constexpr std::chrono::milliseconds IPC_CALL_WAIT{500};
29e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong
30e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hongclass BackgroundTaskState {
31e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hongpublic:
32a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    BackgroundTaskState(std::function<void(void)> &&func)
33a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong            : mFunc(std::forward<decltype(func)>(func)) {}
34e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    void notify() {
35e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong        std::unique_lock<std::mutex> lock(mMutex);
36e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong        mFinished = true;
37e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong        lock.unlock();
38e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong        mCondVar.notify_all();
39e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    }
40e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    template<class C, class D>
41e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    bool wait(std::chrono::time_point<C, D> end) {
42e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong        std::unique_lock<std::mutex> lock(mMutex);
43e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong        mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
44e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong        return mFinished;
45e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    }
46a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    void operator()() {
47a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong        mFunc();
48a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    }
49e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hongprivate:
50e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    std::mutex mMutex;
51e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    std::condition_variable mCondVar;
52e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    bool mFinished = false;
53a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    std::function<void(void)> mFunc;
54e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong};
55e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong
56a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hongvoid *callAndNotify(void *data) {
57a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
58a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    state();
59a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    state.notify();
60a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    return NULL;
61a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong}
62a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong
63e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hongtemplate<class R, class P>
64a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hongbool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) {
65e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    auto now = std::chrono::system_clock::now();
66a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    BackgroundTaskState state{std::forward<decltype(func)>(func)};
67a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    pthread_t thread;
68a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    if (pthread_create(&thread, NULL, callAndNotify, &state)) {
69a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong        std::cerr << "FATAL: could not create background thread." << std::endl;
70a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong        return false;
71a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    }
72e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    bool success = state.wait(now + delay);
73a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    if (!success) {
74a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong        pthread_kill(thread, SIGINT);
75a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    }
76a57dffb151145529e71b22a8d7f985bc1de105f4Yifan Hong    pthread_join(thread, NULL);
77e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    return success;
78e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong}
79e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong
80e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hongtemplate<class Function, class I, class... Args>
81e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hongtypename std::result_of<Function(I *, Args...)>::type
82e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan HongtimeoutIPC(const sp<I> &interfaceObject, Function &&func, Args &&... args) {
83e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    using ::android::hardware::Status;
84e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()};
85e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    auto boundFunc = std::bind(std::forward<Function>(func),
86e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong            interfaceObject.get(), std::forward<Args>(args)...);
87e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    bool success = timeout(IPC_CALL_WAIT, [&ret, &boundFunc] {
8838903c0f88efefec3573d9ff3a8e28131da2f3b5Yifan Hong        ret = std::move(boundFunc());
89e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    });
90e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    if (!success) {
91e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong        return Status::fromStatusT(TIMED_OUT);
92e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    }
93e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong    return ret;
94e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong}
95e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong
96e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong}  // namespace lshal
97e2dadf0c4f132d3a39309f4e274f1a35f7caaaedYifan Hong}  // namespace android
98