• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 MAX_TIMER_ID              0xFF
35 
36 #define INFO_PRINT(fmt, ...) do { \
37         osLog(LOG_INFO, "%s " fmt, "[timer]", ##__VA_ARGS__); \
38     } while (0);
39 
40 #define ERROR_PRINT(fmt, ...) INFO_PRINT("%s" fmt, "ERROR: ", ##__VA_ARGS__)
41 
42 struct Timer {
43     uint64_t      expires; /* time of next expiration */
44     uint64_t      period;  /* 0 for oneshot */
45     uint8_t       id;      /* 0 for disabled */
46     uint8_t       useRtc;  /* 1 for rtc, 0 for tim */
47     uint16_t      tid;     /* we need TID always, for system management */
48     uint32_t      jitterPpm;
49     uint32_t      driftPpm;
50     TaggedPtr     callInfo;
51     void         *callData;
52 };
53 
54 
55 ATOMIC_BITSET_DECL(mTimersValid, MAX_TIMERS, static);
56 static struct SlabAllocator *mInternalEvents;
57 static struct Timer mTimers[MAX_TIMERS];
58 static volatile uint32_t mNextTimerId = 0;
59 
timGetTime(void)60 uint64_t timGetTime(void)
61 {
62     return platGetTicks();
63 }
64 
timDelay(uint32_t length)65 void timDelay(uint32_t length)
66 {
67     uint64_t curTime = timGetTime();
68 
69     while (curTime + length > timGetTime())
70         ;
71 }
72 
timFindTimerById(uint32_t timId)73 static struct Timer *timFindTimerById(uint32_t timId) /* no locks taken. be careful what you do with this */
74 {
75     uint32_t i;
76 
77     for (i = 0; i < MAX_TIMERS; i++)
78         if (mTimers[i].id == timId)
79             return mTimers + i;
80 
81     return NULL;
82 }
83 
timerCallFuncFreeF(void * event)84 static void timerCallFuncFreeF(void* event)
85 {
86     slabAllocatorFree(mInternalEvents, event);
87 }
88 
timCallFunc(struct Timer * tim)89 static void timCallFunc(struct Timer *tim)
90 {
91     struct TimerEvent *evt;
92     TaggedPtr callInfo = tim->callInfo;
93 
94     if (taggedPtrIsPtr(callInfo)) {
95         osSetCurrentTid(tim->tid);
96         ((TimTimerCbkF)taggedPtrToPtr(callInfo))(tim->id, tim->callData);
97     } else {
98         osSetCurrentTid(OS_SYSTEM_TID);
99         if ((evt = slabAllocatorAlloc(mInternalEvents)) != 0) {
100             evt->timerId = tim->id;
101             evt->data = tim->callData;
102             if (!osEnqueuePrivateEvt(EVT_APP_TIMER, evt, timerCallFuncFreeF, tim->tid)) {
103                 ERROR_PRINT("Could not enqueue private timer event\n");
104                 slabAllocatorFree(mInternalEvents, evt);
105             }
106         } else {
107             ERROR_PRINT("Could not allocate an internal event\n");
108         }
109     }
110 }
111 
timFireAsNeededAndUpdateAlarms(void)112 static bool timFireAsNeededAndUpdateAlarms(void)
113 {
114     uint32_t maxDrift = 0, maxJitter = 0, maxErrTotal = 0;
115     bool somethingDone, totalSomethingDone = false;
116     uint64_t nextTimer, expires;
117     uint32_t i;
118     struct Timer *tim;
119 
120     // protect from concurrent execution [timIntHandler() and timTimerSetEx()]
121     uint64_t intSta = cpuIntsOff();
122     uint16_t oldTid = osGetCurrentTid();
123 
124     do {
125         somethingDone = false;
126         nextTimer = 0;
127 
128         for (i = 0, tim = &mTimers[0]; i < MAX_TIMERS; i++, tim++) {
129             if (!tim->id)
130                 continue;
131 
132             if ((!tim->useRtc && tim->expires <= timGetTime()) || (tim->useRtc && tim->expires <= rtcGetTime())) {
133                 somethingDone = true;
134                 if (tim->period) {
135                     tim->expires += tim->period;
136                     timCallFunc(tim);
137                 } else {
138                     timCallFunc(tim);
139                     tim->id = 0;
140                     atomicBitsetClearBit(mTimersValid, i);
141                 }
142             }
143             else {
144                 if (tim->jitterPpm > maxJitter)
145                     maxJitter = tim->jitterPpm;
146                 if (tim->driftPpm > maxDrift)
147                     maxDrift = tim->driftPpm;
148                 if (tim->driftPpm + tim->jitterPpm > maxErrTotal)
149                     maxErrTotal = tim->driftPpm + tim->jitterPpm;
150                 if (tim->useRtc)
151                     expires = tim->expires - rtcGetTime() + timGetTime();
152                 else
153                     expires = tim->expires;
154                 if (!nextTimer || nextTimer > expires)
155                     nextTimer = expires;
156             }
157         }
158 
159         totalSomethingDone = totalSomethingDone || somethingDone;
160 
161     //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
162     } while (somethingDone || (nextTimer && (timGetTime() >= nextTimer || !platSleepClockRequest(nextTimer, maxJitter, maxDrift, maxErrTotal))));
163 
164     if (!nextTimer)
165         platSleepClockRequest(0, 0, 0, 0);
166 
167     osSetCurrentTid(oldTid);
168     cpuIntsRestore(intSta);
169 
170     return totalSomethingDone;
171 }
172 
timTimerSetEx(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,TaggedPtr info,void * data,bool oneShot,bool useRtc)173 static uint32_t timTimerSetEx(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TaggedPtr info, void* data, bool oneShot, bool useRtc)
174 {
175     uint64_t curTime = useRtc ? rtcGetTime() : timGetTime();
176     int32_t idx = atomicBitsetFindClearAndSet(mTimersValid);
177     struct Timer *t;
178     uint16_t timId;
179 
180     if (idx < 0) /* no free timers */{
181         ERROR_PRINT("no free timers\n");
182         return 0;
183     }
184 
185     /* generate next timer ID */
186     do {
187         timId = atomicAdd32bits(&mNextTimerId, 1) & MAX_TIMER_ID;
188     } while (!timId || timFindTimerById(timId));
189 
190     /* grab our struct & fill it in */
191     t = mTimers + idx;
192     t->expires = curTime + length;
193     t->period = oneShot ? 0 : length;
194     t->jitterPpm = jitterPpm;
195     t->driftPpm = driftPpm;
196     t->callInfo = info;
197     t->callData = data;
198     t->useRtc = useRtc;
199     t->tid = osGetCurrentTid();
200 
201     /* as soon as we write timer Id, it becomes valid and might fire */
202     t->id = timId;
203 
204     /* fire as needed & recalc alarms*/
205     timFireAsNeededAndUpdateAlarms();
206 
207     /* woo hoo - done */
208     return timId;
209 }
210 
timTimerSet(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,TimTimerCbkF cbk,void * data,bool oneShot)211 uint32_t timTimerSet(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TimTimerCbkF cbk, void* data, bool oneShot)
212 {
213     return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromPtr(cbk), data, oneShot, false);
214 }
215 
timTimerSetAsApp(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,uint32_t tid,void * data,bool oneShot)216 uint32_t timTimerSetAsApp(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, uint32_t tid, void* data, bool oneShot)
217 {
218     return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromUint(0), data, oneShot, false);
219 }
220 
timTimerSetNew(uint64_t length,const void * data,bool oneShot)221 uint32_t timTimerSetNew(uint64_t length, const void* data, bool oneShot)
222 {
223     return timTimerSetEx(length, 0, 50, taggedPtrMakeFromUint(0), (void *)data, oneShot, true);
224 }
225 
timerEventMatch(uint32_t evtType,const void * evtData,void * context)226 static bool timerEventMatch(uint32_t evtType, const void *evtData, void *context)
227 {
228     struct Timer *t = (struct Timer *)context;
229     union SeosInternalSlabData *da = (union SeosInternalSlabData*)evtData;
230     struct TimerEvent *evt;
231 
232     if (evtType != EVT_PRIVATE_EVT || !da || da->privateEvt.evtType != EVT_APP_TIMER || !da->privateEvt.evtData)
233         return false;
234 
235     evt = (struct TimerEvent *)da->privateEvt.evtData;
236 
237     return evt->timerId == t->id;
238 }
239 
timTimerCancelEx(uint32_t timerId,bool cancelPending)240 bool timTimerCancelEx(uint32_t timerId, bool cancelPending)
241 {
242     uint64_t intState = cpuIntsOff();
243     struct Timer *t = timFindTimerById(timerId);
244 
245     if (t && t->tid == osGetCurrentTid()) {
246         if (cancelPending)
247             osRemovePendingEvents(timerEventMatch, t);
248         t->id = 0; /* this disables it */
249     } else {
250         t = NULL;
251     }
252 
253     cpuIntsRestore(intState);
254 
255     /* this frees struct */
256     if (t) {
257         atomicBitsetClearBit(mTimersValid, t - mTimers);
258         return true;
259     }
260 
261     return false;
262 }
263 
timTimerCancel(uint32_t timerId)264 bool timTimerCancel(uint32_t timerId)
265 {
266     return timTimerCancelEx(timerId, false);
267 }
268 
timTimerCancelAll(uint32_t tid)269 int timTimerCancelAll(uint32_t tid)
270 {
271     uint64_t intState;
272     struct Timer *tim;
273     int i, count;
274 
275     tim = &mTimers[0];
276     intState = cpuIntsOff();
277     for (i = 0, count = 0; i < MAX_TIMERS; ++i, ++tim) {
278         if (tim->tid != tid)
279             continue;
280         count++;
281         osRemovePendingEvents(timerEventMatch, tim);
282         tim->id = 0; /* this disables it */
283         /* this frees struct */
284         atomicBitsetClearBit(mTimersValid, tim - mTimers);
285     }
286     cpuIntsRestore(intState);
287     return count;
288 }
289 
timIntHandler(void)290 bool timIntHandler(void)
291 {
292     return timFireAsNeededAndUpdateAlarms();
293 }
294 
timInit(void)295 void timInit(void)
296 {
297     atomicBitsetInit(mTimersValid, MAX_TIMERS);
298 
299     mInternalEvents = slabAllocatorNew(sizeof(struct TimerEvent), alignof(struct TimerEvent), MAX_INTERNAL_EVENTS);
300 }
301