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 <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/plat.h>
     27 #include <plat/taggedPtr.h>
     28 
     29 #define for_each_item_safe(head, pos, tmp) \
     30     for (pos = (head)->next; tmp = (pos)->next, (pos) != (head); pos = (tmp))
     31 
     32 struct EvtList
     33 {
     34     struct EvtList *next;
     35     struct EvtList *prev;
     36 };
     37 
     38 struct EvtRecord {
     39     struct EvtList item;
     40     uint32_t evtType;
     41     void* evtData;
     42     TaggedPtr evtFreeData;
     43 };
     44 
     45 struct EvtQueue {
     46     struct EvtList head;
     47     struct SlabAllocator *evtsSlab;
     48     EvtQueueForciblyDiscardEvtCbkF forceDiscardCbk;
     49 };
     50 
     51 static inline void __evtListDel(struct EvtList *prev, struct EvtList *next)
     52 {
     53     next->prev = prev;
     54     prev->next = next;
     55 }
     56 
     57 static inline void evtListDel(struct EvtList *entry)
     58 {
     59     __evtListDel(entry->prev, entry->next);
     60     entry->next = entry->prev = NULL;
     61 }
     62 
     63 struct EvtQueue* evtQueueAlloc(uint32_t size, EvtQueueForciblyDiscardEvtCbkF forceDiscardCbk)
     64 {
     65     struct EvtQueue *q = heapAlloc(sizeof(struct EvtQueue));
     66     struct SlabAllocator *slab = slabAllocatorNew(sizeof(struct EvtRecord),
     67                                                   alignof(struct EvtRecord), size);
     68 
     69     if (q && slab) {
     70         q->forceDiscardCbk = forceDiscardCbk;
     71         q->evtsSlab = slab;
     72         q->head.next = &q->head;
     73         q->head.prev = &q->head;
     74         return q;
     75     }
     76 
     77     if (q)
     78         heapFree(q);
     79     if (slab)
     80         slabAllocatorDestroy(slab);
     81 
     82     return NULL;
     83 }
     84 
     85 void evtQueueFree(struct EvtQueue* q)
     86 {
     87     struct EvtList *pos, *tmp;
     88 
     89     for_each_item_safe (&q->head, pos, tmp) {
     90         struct EvtRecord * rec = container_of(pos, struct EvtRecord, item);
     91 
     92         q->forceDiscardCbk(rec->evtType, rec->evtData, rec->evtFreeData);
     93         slabAllocatorFree(q->evtsSlab, rec);
     94     }
     95 
     96     slabAllocatorDestroy(q->evtsSlab);
     97     heapFree(q);
     98 }
     99 
    100 bool evtQueueEnqueue(struct EvtQueue* q, uint32_t evtType, void *evtData,
    101                     TaggedPtr evtFreeData, bool atFront)
    102 {
    103     struct EvtRecord *rec;
    104     uint64_t intSta;
    105     struct EvtList *item = NULL, *a, *b;
    106 
    107     if (!q)
    108         return false;
    109 
    110     rec = slabAllocatorAlloc(q->evtsSlab);
    111     if (!rec) {
    112         struct EvtList *pos;
    113 
    114         intSta = cpuIntsOff();
    115         //find a victim for discarding
    116         for (pos = q->head.next; pos != &q->head; pos = pos->next) {
    117             rec = container_of(pos, struct EvtRecord, item);
    118             if (!(rec->evtType & EVENT_TYPE_BIT_DISCARDABLE))
    119                 continue;
    120             q->forceDiscardCbk(rec->evtType, rec->evtData, rec->evtFreeData);
    121             evtListDel(pos);
    122             item = pos;
    123         }
    124         cpuIntsRestore (intSta);
    125     } else {
    126         item = &rec->item;
    127     }
    128 
    129     if (!item)
    130         return false;
    131 
    132     item->prev = item->next = NULL;
    133 
    134     rec->evtType = evtType;
    135     rec->evtData = evtData;
    136     rec->evtFreeData = evtFreeData;
    137 
    138     intSta = cpuIntsOff();
    139 
    140     if (unlikely(atFront)) {
    141         b = q->head.next;
    142         a = b->prev;
    143     } else {
    144         a = q->head.prev;
    145         b = a->next;
    146     }
    147 
    148     a->next = item;
    149     item->prev = a;
    150     b->prev = item;
    151     item->next = b;
    152 
    153     cpuIntsRestore(intSta);
    154     platWake();
    155     return true;
    156 }
    157 
    158 void evtQueueRemoveAllMatching(struct EvtQueue* q,
    159                                bool (*match)(uint32_t evtType, const void *data, void *context),
    160                                void *context)
    161 {
    162     uint64_t intSta = cpuIntsOff();
    163     struct EvtList *pos, *tmp;
    164 
    165     for_each_item_safe (&q->head, pos, tmp) {
    166         struct EvtRecord * rec = container_of(pos, struct EvtRecord, item);
    167 
    168         if (match(rec->evtType, rec->evtData, context)) {
    169             q->forceDiscardCbk(rec->evtType, rec->evtData, rec->evtFreeData);
    170             evtListDel(pos);
    171             slabAllocatorFree(q->evtsSlab, rec);
    172         }
    173     }
    174     cpuIntsRestore(intSta);
    175 }
    176 
    177 bool evtQueueDequeue(struct EvtQueue* q, uint32_t *evtTypeP, void **evtDataP,
    178                      TaggedPtr *evtFreeDataP, bool sleepIfNone)
    179 {
    180     struct EvtRecord *rec = NULL;
    181     uint64_t intSta;
    182 
    183     while(1) {
    184         struct EvtList *pos;
    185         intSta = cpuIntsOff();
    186 
    187         pos = q->head.next;
    188         if (pos != &q->head) {
    189             rec = container_of(pos, struct EvtRecord, item);
    190             evtListDel(pos);
    191             break;
    192         }
    193         else if (!sleepIfNone)
    194             break;
    195         else if (!timIntHandler()) {
    196             // check for timers
    197             // if any fire, do not sleep (since by the time callbacks run, more might be due)
    198             platSleep();
    199             //first thing when awake: check timers again
    200             timIntHandler();
    201         }
    202         cpuIntsRestore(intSta);
    203     }
    204 
    205     cpuIntsRestore(intSta);
    206 
    207     if (!rec)
    208         return false;
    209 
    210     *evtTypeP = rec->evtType;
    211     *evtDataP = rec->evtData;
    212     *evtFreeDataP = rec->evtFreeData;
    213     slabAllocatorFree(q->evtsSlab, rec);
    214 
    215     return true;
    216 }
    217