• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <cerrno>
16 #include <climits>
17 #include <cstring>
18 #include <ctime>
19 #include <datetime_ex.h>
20 #include <hdf_base.h>
21 #include <hdf_log.h>
22 #include <base/hdi_smq_syncer.h>
23 #include <sys/syscall.h>
24 #include <unistd.h>
25 #include <linux/futex.h>
26 
27 #define HDF_LOG_TAG smq_syncer
28 
29 namespace OHOS {
30 namespace HDI {
31 namespace Base {
SharedMemQueueSyncer(std::atomic<uint32_t> * syncerPtr)32 SharedMemQueueSyncer::SharedMemQueueSyncer(std::atomic<uint32_t> *syncerPtr) : syncAddr_(syncerPtr)
33 {
34 }
35 
Wait(uint32_t bitset,int64_t timeoutNanoSec)36 int SharedMemQueueSyncer::Wait(uint32_t bitset, int64_t timeoutNanoSec)
37 {
38     int ret;
39     while (true) {
40         ret = FutexWait(bitset, timeoutNanoSec);
41         if (ret == -EINTR || ret == -EAGAIN) {
42             HDF_LOGE("wait smq futex %{public}d,try again", ret);
43             continue;
44         }
45         break;
46     }
47 
48     return ret;
49 }
50 
FutexWait(uint32_t bitset,int64_t timeoutNanoSec)51 int SharedMemQueueSyncer::FutexWait(uint32_t bitset, int64_t timeoutNanoSec)
52 {
53     // clean wait bit
54     uint32_t syncWordOld = std::atomic_fetch_and(syncAddr_, ~bitset);
55     // if sync bit already set, not nedd futex wait
56     if (syncWordOld & bitset) {
57         return HDF_SUCCESS;
58     }
59     // futex will check sync word equal this expected val or not. If equal, sleep to wait, else return EAGAIN.
60     uint32_t valParm = syncWordOld & (~bitset);
61     int status;
62     if (timeoutNanoSec > 0) {
63         struct timespec waitTime;
64         TimeoutToRealtime(timeoutNanoSec, waitTime);
65         status = syscall(__NR_futex, syncAddr_, FUTEX_WAIT_BITSET, valParm, &waitTime, NULL, bitset);
66     } else {
67         status = syscall(__NR_futex, syncAddr_, FUTEX_WAIT_BITSET, valParm, NULL, NULL, bitset);
68     }
69     if (status == 0) {
70         syncWordOld = std::atomic_fetch_and(syncAddr_, ~bitset);
71         if ((syncWordOld & bitset) == 0) {
72             return -EINTR;
73         }
74 
75         return status;
76     }
77     status = -errno;
78     if (status != ETIMEDOUT) {
79         HDF_LOGE("failed to wait smq futex, %{publich}d", status);
80     }
81     return status;
82 }
83 
Wake(uint32_t bitset)84 int SharedMemQueueSyncer::Wake(uint32_t bitset)
85 {
86     uint32_t syncWordOld = std::atomic_fetch_or(syncAddr_, bitset);
87     // if sync bit already set, not nedd futex wake
88     if (syncWordOld & bitset) {
89         return HDF_SUCCESS;
90     }
91 
92     int ret = syscall(__NR_futex, syncAddr_, FUTEX_WAKE_BITSET, INT_MAX, 0, 0, bitset);
93     if (ret < 0) {
94         HDF_LOGE("failed to wakeup smq futex, %{public}d", errno);
95         return -errno;
96     }
97 
98     return HDF_SUCCESS;
99 }
100 
TimeoutToRealtime(int64_t timeout,struct timespec & realtime)101 void SharedMemQueueSyncer::TimeoutToRealtime(int64_t timeout, struct timespec &realtime)
102 {
103     constexpr int64_t nano = SEC_TO_NANOSEC;
104 
105     clock_gettime(CLOCK_MONOTONIC, &realtime);
106     int64_t timeoutNanoSec = timeout % nano;
107     int64_t timeoutSec = timeout / nano;
108 
109     if (timeoutNanoSec + realtime.tv_nsec >= nano) {
110         realtime.tv_nsec = (timeoutNanoSec + realtime.tv_nsec) - nano;
111         realtime.tv_sec += timeoutSec + 1;
112     } else {
113         realtime.tv_nsec += timeoutNanoSec;
114         realtime.tv_sec += timeoutSec;
115     }
116 }
117 } // namespace Base
118 } // namespace HDI
119 } // namespace OHOS