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 <platform.h>
     18 #include <eventQ.h>
     19 #include <stddef.h>
     20 #include <timer.h>
     21 #include <stdio.h>
     22 #include <heap.h>
     23 #include <slab.h>
     24 #include <cpu.h>
     25 #include <util.h>
     26 #include <plat/inc/plat.h>
     27 
     28 
     29 struct EvtRecord {
     30     struct EvtRecord *next;
     31     struct EvtRecord *prev;
     32     uint32_t evtType;
     33     void* evtData;
     34     uintptr_t evtFreeData;
     35 };
     36 
     37 struct EvtQueue {
     38     struct EvtRecord *head;
     39     struct EvtRecord *tail;
     40     struct SlabAllocator *evtsSlab;
     41     EvtQueueForciblyDiscardEvtCbkF forceDiscardCbk;
     42 };
     43 
     44 
     45 
     46 struct EvtQueue* evtQueueAlloc(uint32_t size, EvtQueueForciblyDiscardEvtCbkF forceDiscardCbk)
     47 {
     48     struct EvtQueue *q = heapAlloc(sizeof(struct EvtQueue));
     49     struct SlabAllocator *slab = slabAllocatorNew(sizeof(struct EvtRecord), alignof(struct EvtRecord), size);
     50 
     51     if (q && slab) {
     52         q->forceDiscardCbk = forceDiscardCbk;
     53         q->evtsSlab = slab;
     54         q->head = NULL;
     55         q->tail = NULL;
     56         return q;
     57     }
     58 
     59     if (q)
     60         heapFree(q);
     61     if (slab)
     62         slabAllocatorDestroy(slab);
     63 
     64     return NULL;
     65 }
     66 
     67 void evtQueueFree(struct EvtQueue* q)
     68 {
     69     struct EvtRecord *t;
     70 
     71     while (q->head) {
     72         t = q->head;
     73         q->head = q->head->next;
     74         q->forceDiscardCbk(t->evtType, t->evtData, t->evtFreeData);
     75         slabAllocatorFree(q->evtsSlab, t);
     76     }
     77 
     78     slabAllocatorDestroy(q->evtsSlab);
     79     heapFree(q);
     80 }
     81 
     82 bool evtQueueEnqueue(struct EvtQueue* q, uint32_t evtType, void *evtData, uintptr_t evtFreeData, bool atFront)
     83 {
     84     struct EvtRecord *rec;
     85     uint64_t intSta;
     86 
     87     if (!q)
     88         return false;
     89 
     90     rec = slabAllocatorAlloc(q->evtsSlab);
     91     if (!rec) {
     92         intSta = cpuIntsOff();
     93 
     94         //find a victim for discarding
     95         rec = q->head;
     96         while (rec && !(rec->evtType & EVENT_TYPE_BIT_DISCARDABLE))
     97             rec = rec->next;
     98 
     99         if (rec) {
    100             q->forceDiscardCbk(rec->evtType, rec->evtData, rec->evtFreeData);
    101             if (rec->prev)
    102                 rec->prev->next = rec->next;
    103             else
    104                 q->head = rec->next;
    105             if (rec->next)
    106                 rec->next->prev = rec->prev;
    107             else
    108                 q->tail = rec->prev;
    109         }
    110 
    111         cpuIntsRestore (intSta);
    112         if (!rec)
    113            return false;
    114     }
    115 
    116     rec->next = NULL;
    117     rec->evtType = evtType;
    118     rec->evtData = evtData;
    119     rec->evtFreeData = evtFreeData;
    120 
    121     intSta = cpuIntsOff();
    122 
    123     if (atFront) { /* this is almost always not the case */
    124         rec->prev = NULL;
    125         rec->next = q->head;
    126         q->head = rec;
    127         if (q->tail)
    128             rec->next->prev = rec;
    129         else
    130             q->tail = rec;
    131     }
    132     else { /* the common case */
    133         rec->prev = q->tail;
    134         q->tail = rec;
    135         if (q->head)
    136             rec->prev->next = rec;
    137         else
    138             q->head = rec;
    139     }
    140 
    141     cpuIntsRestore(intSta);
    142     platWake();
    143     return true;
    144 }
    145 
    146 bool evtQueueDequeue(struct EvtQueue* q, uint32_t *evtTypeP, void **evtDataP, uintptr_t *evtFreeDataP, bool sleepIfNone)
    147 {
    148     struct EvtRecord *rec = NULL;
    149     uint64_t intSta;
    150 
    151     while(1) {
    152         intSta = cpuIntsOff();
    153 
    154         rec = q->head;
    155         if (rec) {
    156             q->head = rec->next;
    157             if (q->head)
    158                 q->head->prev = NULL;
    159             else
    160                 q->tail = NULL;
    161             break;
    162         }
    163         else if (!sleepIfNone)
    164             break;
    165         else if (!timIntHandler()) { // check for timers. if any fire, do not sleep (since by the time callbacks run, moremight be due)
    166             platSleep();     //sleep
    167             timIntHandler(); //first thing when awake: check timers
    168         }
    169         cpuIntsRestore(intSta);
    170     }
    171 
    172     cpuIntsRestore(intSta);
    173 
    174     if (!rec)
    175         return false;
    176 
    177     *evtTypeP = rec->evtType;
    178     *evtDataP = rec->evtData;
    179     *evtFreeDataP = rec->evtFreeData;
    180     slabAllocatorFree(q->evtsSlab, rec);
    181 
    182     return true;
    183 }
    184 
    185