Home | History | Annotate | Download | only in core
      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