1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cpu/atomicBitset.h>
18 #include <plat/rtc.h>
19 #include <atomicBitset.h>
20 #include <platform.h>
21 #include <atomic.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <timer.h>
25 #include <seos.h>
26 #include <cpu.h>
27 #include <slab.h>
28 #include <util.h>
29
30 #include "seos_priv.h"
31
32 #define MAX_INTERNAL_EVENTS 32 //also used for external app timer() calls
33
34 #define INFO_PRINT(fmt, ...) do { \
35 osLog(LOG_INFO, "%s " fmt, "[timer]", ##__VA_ARGS__); \
36 } while (0);
37
38 #define ERROR_PRINT(fmt, ...) INFO_PRINT("%s" fmt, "ERROR: ", ##__VA_ARGS__)
39
40 struct Timer {
41 uint64_t expires; /* time of next expiration */
42 uint64_t period; /* 0 for oneshot */
43 uint16_t id; /* 0 for disabled */
44 uint16_t tid; /* we need TID always, for system management */
45 uint32_t jitterPpm;
46 uint32_t driftPpm;
47 TaggedPtr callInfo;
48 void *callData;
49 };
50
51
52 ATOMIC_BITSET_DECL(mTimersValid, MAX_TIMERS, static);
53 static struct SlabAllocator *mInternalEvents;
54 static struct Timer mTimers[MAX_TIMERS];
55 static volatile uint32_t mNextTimerId = 0;
56
timGetTime(void)57 uint64_t timGetTime(void)
58 {
59 return platGetTicks();
60 }
61
timFindTimerById(uint32_t timId)62 static struct Timer *timFindTimerById(uint32_t timId) /* no locks taken. be careful what you do with this */
63 {
64 uint32_t i;
65
66 for (i = 0; i < MAX_TIMERS; i++)
67 if (mTimers[i].id == timId)
68 return mTimers + i;
69
70 return NULL;
71 }
72
timerCallFuncFreeF(void * event)73 static void timerCallFuncFreeF(void* event)
74 {
75 slabAllocatorFree(mInternalEvents, event);
76 }
77
timCallFunc(struct Timer * tim)78 static void timCallFunc(struct Timer *tim)
79 {
80 struct TimerEvent *evt;
81 TaggedPtr callInfo = tim->callInfo;
82
83 if (taggedPtrIsPtr(callInfo)) {
84 osSetCurrentTid(tim->tid);
85 ((TimTimerCbkF)taggedPtrToPtr(callInfo))(tim->id, tim->callData);
86 } else {
87 osSetCurrentTid(OS_SYSTEM_TID);
88 if ((evt = slabAllocatorAlloc(mInternalEvents)) != 0) {
89 evt->timerId = tim->id;
90 evt->data = tim->callData;
91 if (!osEnqueuePrivateEvt(EVT_APP_TIMER, evt, timerCallFuncFreeF, tim->tid)) {
92 ERROR_PRINT("Could not enqueue private timer event\n");
93 slabAllocatorFree(mInternalEvents, evt);
94 }
95 } else {
96 ERROR_PRINT("Could not allocate an internal event\n");
97 }
98 }
99 }
100
timFireAsNeededAndUpdateAlarms(void)101 static bool timFireAsNeededAndUpdateAlarms(void)
102 {
103 uint32_t maxDrift = 0, maxJitter = 0, maxErrTotal = 0;
104 bool somethingDone, totalSomethingDone = false;
105 uint64_t nextTimer;
106 uint32_t i;
107 struct Timer *tim;
108
109 // protect from concurrent execution [timIntHandler() and timTimerSetEx()]
110 uint64_t intSta = cpuIntsOff();
111 uint16_t oldTid = osGetCurrentTid();
112
113 do {
114 somethingDone = false;
115 nextTimer = 0;
116
117 for (i = 0, tim = &mTimers[0]; i < MAX_TIMERS; i++, tim++) {
118 if (!tim->id)
119 continue;
120
121 if (tim->expires <= timGetTime()) {
122 somethingDone = true;
123 if (tim->period) {
124 tim->expires += tim->period;
125 timCallFunc(tim);
126 } else {
127 timCallFunc(tim);
128 tim->id = 0;
129 atomicBitsetClearBit(mTimersValid, i);
130 }
131 }
132 else {
133 if (tim->jitterPpm > maxJitter)
134 maxJitter = tim->jitterPpm;
135 if (tim->driftPpm > maxDrift)
136 maxDrift = tim->driftPpm;
137 if (tim->driftPpm + tim->jitterPpm > maxErrTotal)
138 maxErrTotal = tim->driftPpm + tim->jitterPpm;
139 if (!nextTimer || nextTimer > tim->expires)
140 nextTimer = tim->expires;
141 }
142 }
143
144 totalSomethingDone = totalSomethingDone || somethingDone;
145
146 //we loop while loop does something, or while (if next timer exists), it is due by the time loop ends, or platform code fails to set an alarm to wake us for it
147 } while (somethingDone || (nextTimer && (timGetTime() >= nextTimer || !platSleepClockRequest(nextTimer, maxJitter, maxDrift, maxErrTotal))));
148
149 if (!nextTimer)
150 platSleepClockRequest(0, 0, 0, 0);
151
152 osSetCurrentTid(oldTid);
153 cpuIntsRestore(intSta);
154
155 return totalSomethingDone;
156 }
157
timTimerSetEx(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,TaggedPtr info,void * data,bool oneShot)158 static uint32_t timTimerSetEx(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TaggedPtr info, void* data, bool oneShot)
159 {
160 uint64_t curTime = timGetTime();
161 int32_t idx = atomicBitsetFindClearAndSet(mTimersValid);
162 struct Timer *t;
163 uint16_t timId;
164
165 if (idx < 0) /* no free timers */{
166 ERROR_PRINT("no free timers\n");
167 return 0;
168 }
169
170 /* generate next timer ID */
171 do {
172 timId = atomicAdd32bits(&mNextTimerId, 1);
173 } while (!timId || timFindTimerById(timId));
174
175 /* grab our struct & fill it in */
176 t = mTimers + idx;
177 t->expires = curTime + length;
178 t->period = oneShot ? 0 : length;
179 t->jitterPpm = jitterPpm;
180 t->driftPpm = driftPpm;
181 t->callInfo = info;
182 t->callData = data;
183
184 /* as soon as we write timer Id, it becomes valid and might fire */
185 t->id = timId;
186 t->tid = osGetCurrentTid();
187
188 /* fire as needed & recalc alarms*/
189 timFireAsNeededAndUpdateAlarms();
190
191 /* woo hoo - done */
192 return timId;
193 }
194
timTimerSet(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,TimTimerCbkF cbk,void * data,bool oneShot)195 uint32_t timTimerSet(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TimTimerCbkF cbk, void* data, bool oneShot)
196 {
197 return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromPtr(cbk), data, oneShot);
198 }
199
timTimerSetAsApp(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,uint32_t tid,void * data,bool oneShot)200 uint32_t timTimerSetAsApp(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, uint32_t tid, void* data, bool oneShot)
201 {
202 return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromUint(0), data, oneShot);
203 }
204
timTimerSetNew(uint64_t length,const void * data,bool oneShot)205 uint32_t timTimerSetNew(uint64_t length, const void* data, bool oneShot)
206 {
207 return timTimerSetEx(length, 0, 0, taggedPtrMakeFromUint(0), (void *)data, oneShot);
208 }
209
timerEventMatch(uint32_t evtType,const void * evtData,void * context)210 static bool timerEventMatch(uint32_t evtType, const void *evtData, void *context)
211 {
212 struct Timer *t = (struct Timer *)context;
213 union SeosInternalSlabData *da = (union SeosInternalSlabData*)evtData;
214 struct TimerEvent *evt;
215
216 if (evtType != EVT_PRIVATE_EVT || !da || da->privateEvt.evtType != EVT_APP_TIMER || !da->privateEvt.evtData)
217 return false;
218
219 evt = (struct TimerEvent *)da->privateEvt.evtData;
220
221 return evt->timerId == t->id;
222 }
223
timTimerCancelEx(uint32_t timerId,bool cancelPending)224 bool timTimerCancelEx(uint32_t timerId, bool cancelPending)
225 {
226 uint64_t intState = cpuIntsOff();
227 struct Timer *t = timFindTimerById(timerId);
228
229 if (t && t->tid == osGetCurrentTid()) {
230 if (cancelPending)
231 osRemovePendingEvents(timerEventMatch, t);
232 t->id = 0; /* this disables it */
233 } else {
234 t = NULL;
235 }
236
237 cpuIntsRestore(intState);
238
239 /* this frees struct */
240 if (t) {
241 atomicBitsetClearBit(mTimersValid, t - mTimers);
242 return true;
243 }
244
245 return false;
246 }
247
timTimerCancel(uint32_t timerId)248 bool timTimerCancel(uint32_t timerId)
249 {
250 return timTimerCancelEx(timerId, false);
251 }
252
timTimerCancelAll(uint32_t tid)253 int timTimerCancelAll(uint32_t tid)
254 {
255 uint64_t intState;
256 struct Timer *tim;
257 int i, count;
258
259 tim = &mTimers[0];
260 intState = cpuIntsOff();
261 for (i = 0, count = 0; i < MAX_TIMERS; ++i, ++tim) {
262 if (tim->tid != tid)
263 continue;
264 count++;
265 osRemovePendingEvents(timerEventMatch, tim);
266 tim->id = 0; /* this disables it */
267 /* this frees struct */
268 atomicBitsetClearBit(mTimersValid, tim - mTimers);
269 }
270 cpuIntsRestore(intState);
271 return count;
272 }
273
timIntHandler(void)274 bool timIntHandler(void)
275 {
276 return timFireAsNeededAndUpdateAlarms();
277 }
278
timInit(void)279 void timInit(void)
280 {
281 atomicBitsetInit(mTimersValid, MAX_TIMERS);
282
283 mInternalEvents = slabAllocatorNew(sizeof(struct TimerEvent), alignof(struct TimerEvent), MAX_INTERNAL_EVENTS);
284 }
285