Timeout.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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. #include <condition_variable>
  17. #include <chrono>
  18. #include <functional>
  19. #include <mutex>
  20. #include <thread>
  21. #include <hidl/Status.h>
  22. namespace android {
  23. namespace lshal {
  24. static constexpr std::chrono::milliseconds IPC_CALL_WAIT{500};
  25. class BackgroundTaskState {
  26. public:
  27. explicit BackgroundTaskState(std::function<void(void)> &&func)
  28. : mFunc(std::forward<decltype(func)>(func)) {}
  29. void notify() {
  30. std::unique_lock<std::mutex> lock(mMutex);
  31. mFinished = true;
  32. lock.unlock();
  33. mCondVar.notify_all();
  34. }
  35. template<class C, class D>
  36. bool wait(std::chrono::time_point<C, D> end) {
  37. std::unique_lock<std::mutex> lock(mMutex);
  38. mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
  39. return mFinished;
  40. }
  41. void operator()() {
  42. mFunc();
  43. }
  44. private:
  45. std::mutex mMutex;
  46. std::condition_variable mCondVar;
  47. bool mFinished = false;
  48. std::function<void(void)> mFunc;
  49. };
  50. void *callAndNotify(void *data) {
  51. BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
  52. state();
  53. state.notify();
  54. return nullptr;
  55. }
  56. template<class R, class P>
  57. bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) {
  58. auto now = std::chrono::system_clock::now();
  59. BackgroundTaskState state{std::forward<decltype(func)>(func)};
  60. pthread_t thread;
  61. if (pthread_create(&thread, nullptr, callAndNotify, &state)) {
  62. std::cerr << "FATAL: could not create background thread." << std::endl;
  63. return false;
  64. }
  65. bool success = state.wait(now + delay);
  66. if (!success) {
  67. pthread_kill(thread, SIGINT);
  68. }
  69. pthread_join(thread, nullptr);
  70. return success;
  71. }
  72. template<class R, class P, class Function, class I, class... Args>
  73. typename std::result_of<Function(I *, Args...)>::type
  74. timeoutIPC(std::chrono::duration<R, P> wait, const sp<I> &interfaceObject, Function &&func,
  75. Args &&... args) {
  76. using ::android::hardware::Status;
  77. typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()};
  78. auto boundFunc = std::bind(std::forward<Function>(func),
  79. interfaceObject.get(), std::forward<Args>(args)...);
  80. bool success = timeout(wait, [&ret, &boundFunc] {
  81. ret = std::move(boundFunc());
  82. });
  83. if (!success) {
  84. return Status::fromStatusT(TIMED_OUT);
  85. }
  86. return ret;
  87. }
  88. template<class Function, class I, class... Args>
  89. typename std::result_of<Function(I *, Args...)>::type
  90. timeoutIPC(const sp<I> &interfaceObject, Function &&func, Args &&... args) {
  91. return timeoutIPC(IPC_CALL_WAIT, interfaceObject, func, args...);
  92. }
  93. } // namespace lshal
  94. } // namespace android