C++程序  |  217行  |  5.46 KB

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <platform.h>
#include <eventQ.h>
#include <stddef.h>
#include <timer.h>
#include <stdio.h>
#include <heap.h>
#include <slab.h>
#include <cpu.h>
#include <util.h>
#include <plat/plat.h>
#include <plat/taggedPtr.h>

#define for_each_item_safe(head, pos, tmp) \
    for (pos = (head)->next; tmp = (pos)->next, (pos) != (head); pos = (tmp))

struct EvtList
{
    struct EvtList *next;
    struct EvtList *prev;
};

struct EvtRecord {
    struct EvtList item;
    uint32_t evtType;
    void* evtData;
    TaggedPtr evtFreeData;
};

struct EvtQueue {
    struct EvtList head;
    struct SlabAllocator *evtsSlab;
    EvtQueueForciblyDiscardEvtCbkF forceDiscardCbk;
};

static inline void __evtListDel(struct EvtList *prev, struct EvtList *next)
{
    next->prev = prev;
    prev->next = next;
}

static inline void evtListDel(struct EvtList *entry)
{
    __evtListDel(entry->prev, entry->next);
    entry->next = entry->prev = NULL;
}

struct EvtQueue* evtQueueAlloc(uint32_t size, EvtQueueForciblyDiscardEvtCbkF forceDiscardCbk)
{
    struct EvtQueue *q = heapAlloc(sizeof(struct EvtQueue));
    struct SlabAllocator *slab = slabAllocatorNew(sizeof(struct EvtRecord),
                                                  alignof(struct EvtRecord), size);

    if (q && slab) {
        q->forceDiscardCbk = forceDiscardCbk;
        q->evtsSlab = slab;
        q->head.next = &q->head;
        q->head.prev = &q->head;
        return q;
    }

    if (q)
        heapFree(q);
    if (slab)
        slabAllocatorDestroy(slab);

    return NULL;
}

void evtQueueFree(struct EvtQueue* q)
{
    struct EvtList *pos, *tmp;

    for_each_item_safe (&q->head, pos, tmp) {
        struct EvtRecord * rec = container_of(pos, struct EvtRecord, item);

        q->forceDiscardCbk(rec->evtType, rec->evtData, rec->evtFreeData);
        slabAllocatorFree(q->evtsSlab, rec);
    }

    slabAllocatorDestroy(q->evtsSlab);
    heapFree(q);
}

bool evtQueueEnqueue(struct EvtQueue* q, uint32_t evtType, void *evtData,
                    TaggedPtr evtFreeData, bool atFront)
{
    struct EvtRecord *rec;
    uint64_t intSta;
    struct EvtList *item = NULL, *a, *b;

    if (!q)
        return false;

    rec = slabAllocatorAlloc(q->evtsSlab);
    if (!rec) {
        struct EvtList *pos;

        intSta = cpuIntsOff();
        //find a victim for discarding
        for (pos = q->head.next; pos != &q->head; pos = pos->next) {
            rec = container_of(pos, struct EvtRecord, item);
            if (!(rec->evtType & EVENT_TYPE_BIT_DISCARDABLE))
                continue;
            q->forceDiscardCbk(rec->evtType, rec->evtData, rec->evtFreeData);
            evtListDel(pos);
            item = pos;
        }
        cpuIntsRestore (intSta);
    } else {
        item = &rec->item;
    }

    if (!item)
        return false;

    item->prev = item->next = NULL;

    rec->evtType = evtType;
    rec->evtData = evtData;
    rec->evtFreeData = evtFreeData;

    intSta = cpuIntsOff();

    if (unlikely(atFront)) {
        b = q->head.next;
        a = b->prev;
    } else {
        a = q->head.prev;
        b = a->next;
    }

    a->next = item;
    item->prev = a;
    b->prev = item;
    item->next = b;

    cpuIntsRestore(intSta);
    platWake();
    return true;
}

void evtQueueRemoveAllMatching(struct EvtQueue* q,
                               bool (*match)(uint32_t evtType, const void *data, void *context),
                               void *context)
{
    uint64_t intSta = cpuIntsOff();
    struct EvtList *pos, *tmp;

    for_each_item_safe (&q->head, pos, tmp) {
        struct EvtRecord * rec = container_of(pos, struct EvtRecord, item);

        if (match(rec->evtType, rec->evtData, context)) {
            q->forceDiscardCbk(rec->evtType, rec->evtData, rec->evtFreeData);
            evtListDel(pos);
            slabAllocatorFree(q->evtsSlab, rec);
        }
    }
    cpuIntsRestore(intSta);
}

bool evtQueueDequeue(struct EvtQueue* q, uint32_t *evtTypeP, void **evtDataP,
                     TaggedPtr *evtFreeDataP, bool sleepIfNone)
{
    struct EvtRecord *rec = NULL;
    uint64_t intSta;

    while(1) {
        struct EvtList *pos;
        intSta = cpuIntsOff();

        pos = q->head.next;
        if (pos != &q->head) {
            rec = container_of(pos, struct EvtRecord, item);
            evtListDel(pos);
            break;
        }
        else if (!sleepIfNone)
            break;
        else if (!timIntHandler()) {
            // check for timers
            // if any fire, do not sleep (since by the time callbacks run, more might be due)
            platSleep();
            //first thing when awake: check timers again
            timIntHandler();
        }
        cpuIntsRestore(intSta);
    }

    cpuIntsRestore(intSta);

    if (!rec)
        return false;

    *evtTypeP = rec->evtType;
    *evtDataP = rec->evtData;
    *evtFreeDataP = rec->evtFreeData;
    slabAllocatorFree(q->evtsSlab, rec);

    return true;
}