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