Home | History | Annotate | Download | only in src
      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 
     55 uint64_t timGetTime(void)
     56 {
     57     return platGetTicks();
     58 }
     59 
     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 
     71 static void timerCallFuncFreeF(void* event)
     72 {
     73     slabAllocatorFree(mInternalEvents, event);
     74 }
     75 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    242 bool timIntHandler(void)
    243 {
    244     return timFireAsNeededAndUpdateAlarms();
    245 }
    246 
    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