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_timer_callback.h"
17
18#include <cerrno>
19#include <fcntl.h>
20#include <csignal>
21#include <sys/select.h>
22#include <sys/types.h>
23#include <unistd.h>
24
25#include "securec.h"
26
27#include "telephony_log_wrapper.h"
28
29namespace OHOS {
30namespace Telephony {
31void HRilTimerCallback::FdTriggerCallback(int32_t fd, int16_t events, std::shared_ptr<void> param)
32{
33    int32_t ret;
34    int8_t buff[READ_FD_BUFF_SIZE];
35
36    do {
37        ret = read(triggerReadFd_, &buff, sizeof(buff));
38    } while (ret > 0 || (ret < 0 && errno == EINTR));
39}
40
41void HRilTimerCallback::TimerCallback(int32_t fd, int16_t events, std::shared_ptr<void> param)
42{
43    HRilTimerCallbackMessage *pCbMsg = (HRilTimerCallbackMessage *)(param.get());
44    if (pCbMsg == nullptr) {
45        TELEPHONY_LOGE("Argument conversion failed. pCbMsg is nullptr!");
46        return;
47    }
48    if (pCbMsg->func != nullptr) {
49        pCbMsg->func(pCbMsg->param);
50    } else {
51        TELEPHONY_LOGE("HRilTimerCallbackMessage func is nullptr");
52    }
53}
54
55void HRilTimerCallback::OnTriggerEvent()
56{
57    if (std::this_thread::get_id() == eventLoopTid_) {
58        // Write operations are prohibited in read threads.
59        TELEPHONY_LOGE("Currently in a read thread.");
60        return;
61    }
62    int ret;
63    do {
64        ret = write(triggerWriteFd_, " ", 1);
65    } while (ret < 0 && errno == EINTR);
66}
67
68std::shared_ptr<HRilTimerCallbackMessage> HRilTimerCallback::HRilSetTimerCallbackInfo(
69    HRilCallbackFun func, uint8_t *param, const struct timeval *tv)
70{
71    struct timeval timeout;
72    std::shared_ptr<HRilTimerCallbackMessage> pCbMsg = std::make_shared<HRilTimerCallbackMessage>();
73    if (event_ == nullptr || pCbMsg == nullptr) {
74        TELEPHONY_LOGE("HRilSetTimerCallbackInfo event_ or pCbMsg is nullptr");
75        return nullptr;
76    }
77    pCbMsg->func = func;
78    pCbMsg->param = param;
79
80    if (tv == NULL) {
81        (void)memset_s(&timeout, sizeof(timeout), 0, sizeof(timeout));
82    } else {
83        (void)memcpy_s(&timeout, sizeof(timeout), tv, sizeof(timeout));
84    }
85
86    HRilEventMessage eventMsg = { 0 };
87    auto funcCallback =
88        [this](int32_t fd, int16_t events, std::shared_ptr<void> param) { this->TimerCallback(fd, events, param); };
89    event_->SetTimerEvent(eventMsg, event_->IVNALID_FD, false, funcCallback, pCbMsg);
90    event_->AddTimerEvent(eventMsg, timeout);
91    OnTriggerEvent();
92    return pCbMsg;
93}
94
95void HRilTimerCallback::EventLoop()
96{
97    TELEPHONY_LOGI("EventLoop start");
98    eventLoopTid_ = std::this_thread::get_id();
99    event_ = std::make_unique<HRilEvent>();
100    event_->TimerEventInit();
101
102    int32_t pipedes[PIPE_SIZE_MAX];
103    int32_t ret = pipe(pipedes);
104    if (ret < 0) {
105        TELEPHONY_LOGE("Call pipe() is failed, errno:%{public}d", errno);
106        return;
107    }
108
109    triggerReadFd_ = pipedes[0];
110    triggerWriteFd_ = pipedes[1];
111
112    fcntl(triggerReadFd_, F_SETFL, O_NONBLOCK);
113    auto func =
114        [this](int32_t fd, int16_t events, std::shared_ptr<void> param) { this->FdTriggerCallback(fd, events, param); };
115    event_->SetTimerEvent(fdTriggerEvent_, triggerReadFd_, true, func, NULL);
116    event_->AddEventMessage(fdTriggerEvent_);
117    event_->EventMessageLoop();
118    TELEPHONY_LOGE("error in EventMessageLoop errno:%{public}d, isNormalDestory:%{public}d",
119        errno, event_->IsNormalDestory());
120    if (!event_->IsNormalDestory()) {
121        EventLoop();
122    }
123}
124} // namespace Telephony
125} // namespace OHOS