EventFlag.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. #define LOG_TAG "FMQ_EventFlags"
  17. #include <linux/futex.h>
  18. #include <string.h>
  19. #include <sys/mman.h>
  20. #include <sys/syscall.h>
  21. #include <unistd.h>
  22. #include <new>
  23. #include <fmq/EventFlag.h>
  24. #include <utils/Log.h>
  25. #include <utils/SystemClock.h>
  26. namespace android {
  27. namespace hardware {
  28. status_t EventFlag::createEventFlag(int fd, off_t offset, EventFlag** flag) {
  29. if (flag == nullptr) {
  30. return BAD_VALUE;
  31. }
  32. status_t status = NO_MEMORY;
  33. *flag = nullptr;
  34. EventFlag* evFlag = new (std::nothrow) EventFlag(fd, offset, &status);
  35. if (evFlag != nullptr) {
  36. if (status == NO_ERROR) {
  37. *flag = evFlag;
  38. } else {
  39. delete evFlag;
  40. }
  41. }
  42. return status;
  43. }
  44. status_t EventFlag::createEventFlag(std::atomic<uint32_t>* fwAddr,
  45. EventFlag** flag) {
  46. if (flag == nullptr) {
  47. return BAD_VALUE;
  48. }
  49. status_t status = NO_MEMORY;
  50. *flag = nullptr;
  51. EventFlag* evFlag = new (std::nothrow) EventFlag(fwAddr, &status);
  52. if (evFlag != nullptr) {
  53. if (status == NO_ERROR) {
  54. *flag = evFlag;
  55. } else {
  56. delete evFlag;
  57. }
  58. }
  59. return status;
  60. }
  61. /*
  62. * mmap memory for the futex word
  63. */
  64. EventFlag::EventFlag(int fd, off_t offset, status_t* status) {
  65. mEfWordPtr = static_cast<std::atomic<uint32_t>*>(mmap(NULL,
  66. sizeof(std::atomic<uint32_t>),
  67. PROT_READ | PROT_WRITE,
  68. MAP_SHARED, fd, offset));
  69. mEfWordNeedsUnmapping = true;
  70. if (mEfWordPtr != MAP_FAILED) {
  71. *status = NO_ERROR;
  72. } else {
  73. *status = -errno;
  74. ALOGE("Attempt to mmap event flag word failed: %s\n", strerror(errno));
  75. }
  76. }
  77. /*
  78. * Use this constructor if we already know where the futex word for
  79. * the EventFlag group lives.
  80. */
  81. EventFlag::EventFlag(std::atomic<uint32_t>* fwAddr, status_t* status) {
  82. *status = NO_ERROR;
  83. if (fwAddr == nullptr) {
  84. *status = BAD_VALUE;
  85. } else {
  86. mEfWordPtr = fwAddr;
  87. }
  88. }
  89. /*
  90. * Set the specified bits of the futex word here and wake up any
  91. * thread waiting on any of the bits.
  92. */
  93. status_t EventFlag::wake(uint32_t bitmask) {
  94. /*
  95. * Return early if there are no set bits in bitmask.
  96. */
  97. if (bitmask == 0) {
  98. return NO_ERROR;
  99. }
  100. status_t status = NO_ERROR;
  101. uint32_t old = std::atomic_fetch_or(mEfWordPtr, bitmask);
  102. /*
  103. * No need to call FUTEX_WAKE_BITSET if there were deferred wakes
  104. * already available for all set bits from bitmask.
  105. */
  106. if ((~old & bitmask) != 0) {
  107. int ret = syscall(__NR_futex, mEfWordPtr, FUTEX_WAKE_BITSET,
  108. INT_MAX, NULL, NULL, bitmask);
  109. if (ret == -1) {
  110. status = -errno;
  111. ALOGE("Error in event flag wake attempt: %s\n", strerror(errno));
  112. }
  113. }
  114. return status;
  115. }
  116. /*
  117. * Wait for any of the bits in the bitmask to be set
  118. * and return which bits caused the return.
  119. */
  120. status_t EventFlag::waitHelper(uint32_t bitmask, uint32_t* efState, int64_t timeoutNanoSeconds) {
  121. /*
  122. * Return early if there are no set bits in bitmask.
  123. */
  124. if (bitmask == 0 || efState == nullptr) {
  125. return BAD_VALUE;
  126. }
  127. status_t status = NO_ERROR;
  128. uint32_t old = std::atomic_fetch_and(mEfWordPtr, ~bitmask);
  129. uint32_t setBits = old & bitmask;
  130. /*
  131. * If there was a deferred wake available, no need to call FUTEX_WAIT_BITSET.
  132. */
  133. if (setBits != 0) {
  134. *efState = setBits;
  135. return status;
  136. }
  137. uint32_t efWord = old & ~bitmask;
  138. /*
  139. * The syscall will put the thread to sleep only
  140. * if the futex word still contains the expected
  141. * value i.e. efWord. If the futex word contents have
  142. * changed, it fails with the error EAGAIN; If a timeout
  143. * is specified and exceeded the syscall fails with ETIMEDOUT.
  144. */
  145. int ret = 0;
  146. if (timeoutNanoSeconds) {
  147. struct timespec waitTimeAbsolute;
  148. addNanosecondsToCurrentTime(timeoutNanoSeconds, &waitTimeAbsolute);
  149. ret = syscall(__NR_futex, mEfWordPtr, FUTEX_WAIT_BITSET,
  150. efWord, &waitTimeAbsolute, NULL, bitmask);
  151. } else {
  152. ret = syscall(__NR_futex, mEfWordPtr, FUTEX_WAIT_BITSET, efWord, NULL, NULL, bitmask);
  153. }
  154. if (ret == -1) {
  155. status = -errno;
  156. if (status != -EAGAIN && status != -ETIMEDOUT) {
  157. ALOGE("Event flag wait was unsuccessful: %s\n", strerror(errno));
  158. }
  159. *efState = 0;
  160. } else {
  161. old = std::atomic_fetch_and(mEfWordPtr, ~bitmask);
  162. *efState = old & bitmask;
  163. if (*efState == 0) {
  164. /* Return -EINTR for a spurious wakeup */
  165. status = -EINTR;
  166. }
  167. }
  168. return status;
  169. }
  170. /*
  171. * Wait for any of the bits in the bitmask to be set
  172. * and return which bits caused the return. If 'retry'
  173. * is true, wait again on a spurious wake-up.
  174. */
  175. status_t EventFlag::wait(uint32_t bitmask,
  176. uint32_t* efState,
  177. int64_t timeoutNanoSeconds,
  178. bool retry) {
  179. if (!retry) {
  180. return waitHelper(bitmask, efState, timeoutNanoSeconds);
  181. }
  182. bool shouldTimeOut = timeoutNanoSeconds != 0;
  183. int64_t prevTimeNs = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
  184. status_t status;
  185. while (true) {
  186. if (shouldTimeOut) {
  187. int64_t currentTimeNs = android::elapsedRealtimeNano();
  188. /*
  189. * Decrement TimeOutNanos to account for the time taken to complete the last
  190. * iteration of the while loop.
  191. */
  192. timeoutNanoSeconds -= currentTimeNs - prevTimeNs;
  193. prevTimeNs = currentTimeNs;
  194. if (timeoutNanoSeconds <= 0) {
  195. status = -ETIMEDOUT;
  196. *efState = 0;
  197. break;
  198. }
  199. }
  200. status = waitHelper(bitmask, efState, timeoutNanoSeconds);
  201. if ((status != -EAGAIN) && (status != -EINTR)) {
  202. break;
  203. }
  204. }
  205. return status;
  206. }
  207. status_t EventFlag::unmapEventFlagWord(std::atomic<uint32_t>* efWordPtr,
  208. bool* efWordNeedsUnmapping) {
  209. status_t status = NO_ERROR;
  210. if (*efWordNeedsUnmapping) {
  211. int ret = munmap(efWordPtr, sizeof(std::atomic<uint32_t>));
  212. if (ret != 0) {
  213. status = -errno;
  214. ALOGE("Error in deleting event flag group: %s\n", strerror(errno));
  215. }
  216. *efWordNeedsUnmapping = false;
  217. }
  218. return status;
  219. }
  220. status_t EventFlag::deleteEventFlag(EventFlag** evFlag) {
  221. if (evFlag == nullptr || *evFlag == nullptr) {
  222. return BAD_VALUE;
  223. }
  224. status_t status = unmapEventFlagWord((*evFlag)->mEfWordPtr,
  225. &(*evFlag)->mEfWordNeedsUnmapping);
  226. delete *evFlag;
  227. *evFlag = nullptr;
  228. return status;
  229. }
  230. void EventFlag::addNanosecondsToCurrentTime(int64_t nanoSeconds, struct timespec* waitTime) {
  231. static constexpr int64_t kNanosPerSecond = 1000000000;
  232. clock_gettime(CLOCK_MONOTONIC, waitTime);
  233. waitTime->tv_sec += nanoSeconds / kNanosPerSecond;
  234. waitTime->tv_nsec += nanoSeconds % kNanosPerSecond;
  235. if (waitTime->tv_nsec >= kNanosPerSecond) {
  236. waitTime->tv_sec++;
  237. waitTime->tv_nsec -= kNanosPerSecond;
  238. }
  239. }
  240. EventFlag::~EventFlag() {
  241. unmapEventFlagWord(mEfWordPtr, &mEfWordNeedsUnmapping);
  242. }
  243. } // namespace hardware
  244. } // namespace android