• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-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 
16 #include "hci_watcher.h"
17 #include <thread>
18 #include <unistd.h>
19 #include <sys/select.h>
20 #include <sys/syscall.h>
21 #include <hdf_log.h>
22 #include "bt_hal_constant.h"
23 
24 namespace OHOS {
25 namespace HDI {
26 namespace Bluetooth {
27 namespace Hci {
HciWatcher()28 HciWatcher::HciWatcher()
29 {}
30 
~HciWatcher()31 HciWatcher::~HciWatcher()
32 {
33     Stop();
34 }
35 
AddFdToWatcher(int fd,HciDataCallback callback)36 bool HciWatcher::AddFdToWatcher(int fd, HciDataCallback callback)
37 {
38     std::lock_guard<std::mutex> lock(fdsMutex_);
39     fds_[fd] = callback;
40     ThreadWakeup();
41     return true;
42 }
43 
RemoveFdToWatcher(int fd)44 bool HciWatcher::RemoveFdToWatcher(int fd)
45 {
46     std::lock_guard<std::mutex> lock(fdsMutex_);
47     fds_.erase(fd);
48     ThreadWakeup();
49     return true;
50 }
51 
SetTimeout(std::chrono::milliseconds timeout,TimeoutCallback callback)52 bool HciWatcher::SetTimeout(std::chrono::milliseconds timeout, TimeoutCallback callback)
53 {
54     std::chrono::seconds seconds = std::chrono::duration_cast<std::chrono::seconds>(timeout);
55     std::lock_guard<std::mutex> lock(timeoutMutex_);
56     timeoutTimer_.tv_sec = seconds.count();
57     timeoutTimer_.tv_usec = (timeout - seconds).count();
58     timeoutCallback_ = callback;
59     ThreadWakeup();
60     return true;
61 }
62 
Start()63 bool HciWatcher::Start()
64 {
65     if (running_.exchange(true)) {
66         return true;
67     }
68 
69     if (pipe(wakeupPipe_) != 0) {
70         HDF_LOGE("HciWatcher create pipe failed.");
71         running_.exchange(false);
72         return false;
73     }
74 
75     thread_ = std::thread(std::bind(&HciWatcher::WatcherThread, this));
76     if (!thread_.joinable()) {
77         HDF_LOGE("thread is not joinable.");
78         running_.exchange(false);
79         return false;
80     }
81 
82     int policy = BT_THREAD_POLICY;
83     sched_param params = {.sched_priority = BT_THREAD_PRIORITY};
84     if (pthread_setschedparam(thread_.native_handle(), policy, &params) != 0) {
85         HDF_LOGW("pthread_setschedparam failed tid[%lu] policy[%d]", thread_.native_handle(), policy);
86     }
87 
88     return true;
89 }
90 
Stop()91 bool HciWatcher::Stop()
92 {
93     if (!running_.exchange(false)) {
94         return true;
95     }
96 
97     ThreadWakeup();
98     thread_.join();
99 
100     close(wakeupPipe_[0]);
101     close(wakeupPipe_[1]);
102 
103     return true;
104 }
105 
WatcherThread()106 void HciWatcher::WatcherThread()
107 {
108     fd_set readFds;
109     int nfds;
110     timeval *timeout = nullptr;
111 
112     while (running_) {
113         FD_ZERO(&readFds);
114         FD_SET(wakeupPipe_[0], &readFds);
115         nfds = wakeupPipe_[0];
116         {
117             std::lock_guard<std::mutex> lock(fdsMutex_);
118             for (auto &&fd : fds_) {
119                 FD_SET(fd.first, &readFds);
120                 nfds = std::max(fd.first, nfds);
121             }
122         }
123 
124         {
125             std::lock_guard<std::mutex> lock(timeoutMutex_);
126             if (timeoutTimer_.tv_sec == 0 && timeoutTimer_.tv_usec == 0) {
127                 timeout = nullptr;
128             } else {
129                 timeout = &timeoutTimer_;
130             }
131         }
132 
133         int ret = select(nfds + 1, &readFds, nullptr, nullptr, timeout);
134         if (ret < 0) {
135             continue;
136         } else if (ret == 0) {
137             TimeoutCallback callback;
138             {
139                 std::lock_guard<std::mutex> lock(timeoutMutex_);
140                 callback = timeoutCallback_;
141             }
142             if (callback) {
143                 callback();
144             }
145         } else {
146             if (FD_ISSET(wakeupPipe_[0], &readFds)) {
147                 uint8_t buff;
148                 TEMP_FAILURE_RETRY(read(wakeupPipe_[0], &buff, sizeof(buff)));
149             }
150             std::lock_guard<std::mutex> lock(fdsMutex_);
151             for (auto &&fd : fds_) {
152                 if (FD_ISSET(fd.first, &readFds)) {
153                     fd.second(fd.first);
154                 }
155             }
156         }
157     }
158 }
159 
ThreadWakeup()160 void HciWatcher::ThreadWakeup()
161 {
162     uint8_t buff = 0;
163     TEMP_FAILURE_RETRY(write(wakeupPipe_[1], &buff, sizeof(buff)));
164 }
165 }  // namespace Hci
166 }  // namespace Bluetooth
167 }  // namespace HDI
168 }  // namespace OHOS