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