• 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 "platform/include/alarm.h"
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <sys/timerfd.h>
20 #include "platform/include/thread.h"
21 #include "platform/include/reactor.h"
22 #include "platform/include/mutex.h"
23 #include "platform/include/platform_def.h"
24 #include "securec.h"
25 
26 #define BT_CLOCK_MONOTONIC CLOCK_MONOTONIC
27 
28 static const char *g_defaultName = "bt-alarm";
29 
30 static Thread *g_alarmThread = NULL;
31 
32 typedef struct {
33     void *parameter;
34     AlarmCallback run;
35 } AlarmContext;
36 
37 typedef struct Alarm {
38     int timerFd;
39     Mutex *mutex;
40     bool isPeriodic;
41     AlarmContext context;
42     ReactorItem *reactorItem;
43     char name[ALARM_NAME_SIZE + 1];
44 } AlarmInternal;
45 
AlarmModuleInit()46 int32_t AlarmModuleInit()
47 {
48     g_alarmThread = ThreadCreate("Stack-Alarm");
49     if (g_alarmThread == NULL) {
50         LOG_ERROR("Alarm thread create failed.");
51         return -1;
52     }
53     return 0;
54 }
55 
AlarmModuleCleanup()56 void AlarmModuleCleanup()
57 {
58     if (g_alarmThread == NULL) {
59         return;
60     }
61 
62     ThreadDelete(g_alarmThread);
63     g_alarmThread = NULL;
64 }
65 
AlarmNotify(void * parameter)66 static void AlarmNotify(void *parameter)
67 {
68     Alarm *alarm = (Alarm *)parameter;
69 
70     MutexLock(alarm->mutex);
71 
72     AlarmCallback run = alarm->context.run;
73     void *param = alarm->context.parameter;
74 
75     uint64_t value = 0;
76     int ret = read(alarm->timerFd, &value, sizeof(uint64_t));
77     if (ret == sizeof(uint64_t)) {
78         if (value > 1) {
79             LOG_WARN("Alarm has expired more than one times.");
80         }
81     } else {
82         if (errno == EAGAIN) {
83             LOG_INFO("Alarm is stopped or reset before callback called.");
84         } else {
85             LOG_ERROR("Alarm read value failed, error no: %{public}d.", errno);
86         }
87         run = NULL;
88     }
89     MutexUnlock(alarm->mutex);
90 
91     if (run) {
92         run(param);
93     }
94 }
95 
AlarmCreate(const char * name,const bool isPeriodic)96 Alarm *AlarmCreate(const char *name, const bool isPeriodic)
97 {
98     Alarm *alarm = (Alarm *)calloc(1, (sizeof(Alarm)));
99     if (alarm == NULL) {
100         LOG_ERROR("Failed to call calloc in func AlarmCreate");
101         return NULL;
102     }
103 
104     if (name != NULL) {
105         (void)strncpy_s(alarm->name, ALARM_NAME_SIZE + 1, name, ALARM_NAME_SIZE);
106     } else {
107         (void)strncpy_s(alarm->name, ALARM_NAME_SIZE + 1, g_defaultName, ALARM_NAME_SIZE);
108     }
109 
110     int timerFd = timerfd_create(BT_CLOCK_MONOTONIC, TFD_NONBLOCK);
111     if (timerFd == -1) {
112         LOG_ERROR("Alarm create timer-fd failed, error no: %{public}d.", errno);
113         goto ERROR;
114     }
115 
116     Mutex *mutex = MutexCreate();
117     if (mutex == NULL) {
118         close(timerFd);
119         LOG_ERROR("Alarm create mutex failed.");
120         goto ERROR;
121     }
122 
123     alarm->timerFd = timerFd;
124     alarm->isPeriodic = isPeriodic;
125     alarm->mutex = mutex;
126 
127     ReactorItem *item =
128         ReactorRegister(ThreadGetReactor(g_alarmThread), alarm->timerFd, (void *)alarm, AlarmNotify, NULL);
129     if (item == NULL) {
130         close(timerFd);
131         LOG_ERROR("Alarm register reactor failed.");
132         goto ERROR;
133     }
134 
135     alarm->reactorItem = item;
136 
137     return alarm;
138 
139 ERROR:
140 
141     if (alarm != NULL) {
142         MutexDelete(alarm->mutex);
143         free(alarm);
144     }
145     return NULL;
146 }
147 
AlarmDelete(Alarm * alarm)148 void AlarmDelete(Alarm *alarm)
149 {
150     if (alarm == NULL) {
151         return;
152     }
153 
154     ReactorUnregister(alarm->reactorItem);
155     close(alarm->timerFd);
156     MutexDelete(alarm->mutex);
157     free(alarm);
158 }
159 
AlarmSet(Alarm * alarm,uint64_t timeMs,AlarmCallback callback,void * parameter)160 int32_t AlarmSet(Alarm *alarm, uint64_t timeMs, AlarmCallback callback, void *parameter)
161 {
162     ASSERT(alarm);
163 
164     MutexLock(alarm->mutex);
165 
166     alarm->context.parameter = parameter;
167     alarm->context.run = callback;
168 
169     struct itimerspec its = {0};
170     its.it_value.tv_sec = timeMs / MS_PER_SECOND;
171     its.it_value.tv_nsec = (timeMs % MS_PER_SECOND) * NS_PER_MS;
172     if (alarm->isPeriodic) {
173         its.it_interval = its.it_value;
174     }
175 
176     if (timerfd_settime(alarm->timerFd, 0, &its, NULL) == -1) {
177         LOG_ERROR("Alarm settime failed, error no: %{public}d.", errno);
178         MutexUnlock(alarm->mutex);
179         return -1;
180     }
181 
182     MutexUnlock(alarm->mutex);
183     return 0;
184 }
185 
AlarmCancel(Alarm * alarm)186 void AlarmCancel(Alarm *alarm)
187 {
188     ASSERT(alarm);
189 
190     MutexLock(alarm->mutex);
191     struct itimerspec its = {0};
192     if (timerfd_settime(alarm->timerFd, 0, &its, NULL) == -1) {
193         LOG_ERROR("Alarm cancel: settime 0 failed, error no: %{public}d.", errno);
194     }
195     MutexUnlock(alarm->mutex);
196 }