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