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 32struct EvtList 33{ 34 struct EvtList *next; 35 struct EvtList *prev; 36}; 37 38struct EvtRecord { 39 struct EvtList item; 40 uint32_t evtType; 41 void* evtData; 42 TaggedPtr evtFreeData; 43}; 44 45struct EvtQueue { 46 struct EvtList head; 47 struct SlabAllocator *evtsSlab; 48 EvtQueueForciblyDiscardEvtCbkF forceDiscardCbk; 49}; 50 51static inline void __evtListDel(struct EvtList *prev, struct EvtList *next) 52{ 53 next->prev = prev; 54 prev->next = next; 55} 56 57static inline void evtListDel(struct EvtList *entry) 58{ 59 __evtListDel(entry->prev, entry->next); 60 entry->next = entry->prev = NULL; 61} 62 63struct 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 85void 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 100bool 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 158void 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 177bool 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