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 60 uint64_t timGetTime(void) 61 { 62 return platGetTicks(); 63 } 64 65 void timDelay(uint32_t length) 66 { 67 uint64_t curTime = timGetTime(); 68 69 while (curTime + length > timGetTime()) 70 ; 71 } 72 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 84 static void timerCallFuncFreeF(void* event) 85 { 86 slabAllocatorFree(mInternalEvents, event); 87 } 88 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 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 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 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 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 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 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 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 264 bool timTimerCancel(uint32_t timerId) 265 { 266 return timTimerCancelEx(timerId, false); 267 } 268 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 290 bool timIntHandler(void) 291 { 292 return timFireAsNeededAndUpdateAlarms(); 293 } 294 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