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