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 57 uint64_t timGetTime(void) 58 { 59 return platGetTicks(); 60 } 61 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 73 static void timerCallFuncFreeF(void* event) 74 { 75 slabAllocatorFree(mInternalEvents, event); 76 } 77 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 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 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 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 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 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 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 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 248 bool timTimerCancel(uint32_t timerId) 249 { 250 return timTimerCancelEx(timerId, false); 251 } 252 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 274 bool timIntHandler(void) 275 { 276 return timFireAsNeededAndUpdateAlarms(); 277 } 278 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