• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "hril_event.h"
17 
18 #include <cerrno>
19 #include <fcntl.h>
20 #include <sys/select.h>
21 #include <sys/time.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 
25 #include "securec.h"
26 
27 #include "telephony_log_wrapper.h"
28 
29 namespace OHOS {
30 namespace Telephony {
GetNowTime(struct timeval & tv)31 void HRilEvent::GetNowTime(struct timeval &tv)
32 {
33     const int32_t TIME_UNIT = 1000;
34     struct timespec ts;
35     clock_gettime(CLOCK_MONOTONIC, &ts);
36     tv.tv_sec = ts.tv_sec;
37     tv.tv_usec = ts.tv_nsec / TIME_UNIT;
38 }
39 
GetNextTimeOut(struct timeval & tv)40 bool HRilEvent::GetNextTimeOut(struct timeval &tv)
41 {
42     std::list<HRilEventMessage>::iterator eventIt = timerList_.begin();
43     if (eventIt == timerList_.end() || timerList_.empty()) {
44         return false;
45     }
46 
47     struct timeval now;
48     GetNowTime(now);
49     TELEPHONY_LOGI("now = %{public}ds + %{public}dus", (int32_t)now.tv_sec, (int32_t)now.tv_usec);
50     TELEPHONY_LOGI(
51         "next = %{public}ds + %{public}dus", (int32_t)eventIt->timeout.tv_sec, (int32_t)eventIt->timeout.tv_usec);
52     if (timercmp(&eventIt->timeout, &now, >)) {
53         timersub(&eventIt->timeout, &now, &tv);
54     } else {
55         // timer already expired.
56         tv.tv_sec = tv.tv_usec = 0;
57     }
58     return true;
59 }
60 
ProcessTimerList()61 void HRilEvent::ProcessTimerList()
62 {
63     struct timeval now;
64     std::lock_guard<std::mutex> mutexLock(listLock_);
65     std::list<HRilEventMessage>::iterator eventIt = timerList_.begin();
66     GetNowTime(now);
67 
68     TELEPHONY_LOGI("finding for timers <= %{public}ds + %{public}dus", (int32_t)now.tv_sec, (int32_t)now.tv_usec);
69     while ((eventIt != timerList_.end()) && (timercmp(&now, &eventIt->timeout, >))) {
70         HRilEventMessage evMsg = {};
71         evMsg.fd = eventIt->fd;
72         evMsg.func = eventIt->func;
73         evMsg.index = eventIt->index;
74         evMsg.param = eventIt->param;
75         evMsg.timeout = eventIt->timeout;
76         pendingList_.push_back(evMsg);
77         eventIt = timerList_.erase(eventIt);
78     }
79 }
80 
ProcessPendingList()81 void HRilEvent::ProcessPendingList()
82 {
83     std::list<HRilEventMessage>::iterator eventIt = pendingList_.begin();
84     while (eventIt != pendingList_.end()) {
85         if (eventIt->func != nullptr) {
86             eventIt->func(eventIt->fd, 0, eventIt->param);
87         }
88         eventIt = pendingList_.erase(eventIt);
89     }
90 }
91 
EraseListenEvent(HRilEventMessage & eventMsg,int32_t index)92 void HRilEvent::EraseListenEvent(HRilEventMessage &eventMsg, int32_t index)
93 {
94     listenEventTable_[index] = nullptr;
95     eventMsg.index = DEFAULT_INDEX;
96 
97     FD_CLR(eventMsg.fd, &readFds_);
98 
99     if (eventMsg.fd + 1 == nfds_) {
100         int32_t n = 0;
101         for (auto msg : listenEventTable_) {
102             if ((msg != nullptr) && (msg->fd > n)) {
103                 n = msg->fd;
104             }
105         }
106         nfds_ = n + 1;
107         TELEPHONY_LOGI("Updated nfds = %{public}d", nfds_);
108     }
109 }
110 
ProcessEvents(fd_set * rfds,int32_t number)111 void HRilEvent::ProcessEvents(fd_set *rfds, int32_t number)
112 {
113     auto it = listenEventTable_.begin();
114     for (; (it != listenEventTable_.end()) && (number > 0); ++it) {
115         if (*it != nullptr && FD_ISSET((*it)->fd, rfds)) {
116             pendingList_.push_back(*(*it));
117             if ((*it)->isHolding == false) {
118                 EraseListenEvent(*(*it), (*it)->index);
119             }
120             number--;
121         }
122     }
123 }
124 
TimerEventInit()125 void HRilEvent::TimerEventInit()
126 {
127     FD_ZERO(&readFds_);
128     timerList_.clear();
129     pendingList_.clear();
130     listenEventTable_.clear();
131     for (int32_t i = 0; i < LISTEN_FD_EVENTS_MAX; i++) {
132         listenEventTable_.push_back(nullptr);
133     }
134 }
135 
AddTimerEvent(HRilEventMessage & eventMsg,const struct timeval & tv)136 void HRilEvent::AddTimerEvent(HRilEventMessage &eventMsg, const struct timeval &tv)
137 {
138     std::lock_guard<std::mutex> mutexLock(listLock_);
139     struct timeval now;
140     eventMsg.fd = IVNALID_FD; // make sure fd is invalid
141 
142     GetNowTime(now);
143     timeradd(&now, &tv, &eventMsg.timeout);
144 
145     std::list<HRilEventMessage>::iterator it = timerList_.begin();
146     for (; it != timerList_.end(); ++it) {
147         if (timercmp(&it->timeout, &eventMsg.timeout, >)) {
148             timerList_.insert(it, eventMsg);
149             return;
150         }
151     }
152     if (it == timerList_.end()) {
153         timerList_.push_back(eventMsg);
154     }
155 }
156 
SetTimerEvent(HRilEventMessage & eventMsg,int32_t fd,bool isHolding,HRilEventCallback func,std::shared_ptr<void> param)157 void HRilEvent::SetTimerEvent(
158     HRilEventMessage &eventMsg, int32_t fd, bool isHolding, HRilEventCallback func, std::shared_ptr<void> param)
159 {
160     (void)memset_s(&eventMsg, sizeof(HRilEventMessage), 0, sizeof(HRilEventMessage));
161     eventMsg.fd = fd;
162     eventMsg.index = DEFAULT_INDEX;
163     eventMsg.func = func;
164     eventMsg.param = param;
165     eventMsg.isHolding = isHolding;
166     fcntl(fd, F_SETFL, O_NONBLOCK);
167 }
168 
AddEventMessage(const HRilEventMessage & eventMsg)169 void HRilEvent::AddEventMessage(const HRilEventMessage &eventMsg)
170 {
171     std::lock_guard<std::mutex> mutexLock(listLock_);
172     for (int32_t i = 0; i < LISTEN_FD_EVENTS_MAX; i++) {
173         if (listenEventTable_[i] == nullptr) {
174             listenEventTable_[i] = const_cast<HRilEventMessage *>(&eventMsg);
175             listenEventTable_[i]->index = i;
176             FD_SET(eventMsg.fd, &readFds_);
177             if (eventMsg.fd >= nfds_) {
178                 nfds_ = eventMsg.fd + 1;
179             }
180             break;
181         }
182     }
183 }
184 
RemoveEventMessage(HRilEventMessage & eventMsg)185 void HRilEvent::RemoveEventMessage(HRilEventMessage &eventMsg)
186 {
187     std::lock_guard<std::mutex> mutexLock(listLock_);
188     if (eventMsg.index < 0 || eventMsg.index >= LISTEN_FD_EVENTS_MAX) {
189         TELEPHONY_LOGE("Invalid event message! index:%{pubulic}d", eventMsg.index);
190         return;
191     }
192     EraseListenEvent(eventMsg, eventMsg.index);
193 }
194 
EventMessageLoop()195 void HRilEvent::EventMessageLoop()
196 {
197     int32_t ret;
198     fd_set rfds;
199     struct timeval timeout;
200     struct timeval *pTimeOut;
201 
202     TELEPHONY_LOGI("****** EventMessageLoop start ******");
203     while (1) {
204         (void)memcpy_s(&rfds, sizeof(fd_set), &readFds_, sizeof(fd_set));
205         if (!GetNextTimeOut(timeout)) {
206             // Enter blocking wait without setting a timer.
207             TELEPHONY_LOGI("Enter blocking wait without setting a timer.");
208             pTimeOut = nullptr;
209         } else {
210             TELEPHONY_LOGI(
211                 "Setting timeout for %{public}ds + %{public}dus", (int32_t)timeout.tv_sec, (int32_t)timeout.tv_usec);
212             pTimeOut = &timeout;
213         }
214         ret = select(nfds_, &rfds, nullptr, nullptr, pTimeOut);
215         TELEPHONY_LOGI("There are %{public}d events fired.", ret);
216         if (ret < 0) {
217             if (errno == EINTR) {
218                 continue;
219             }
220             TELEPHONY_LOGE("select error (%{public}d)", errno);
221             return;
222         }
223         ProcessTimerList();
224         ProcessEvents(&rfds, ret);
225         ProcessPendingList();
226     }
227 }
228 } // namespace Telephony
229 } // namespace OHOS