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 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