|  |  | 
|  | /* | 
|  | * Copyright 2006 The Android Open Source Project | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include "SkEvent.h" | 
|  |  | 
|  | void SkEvent::initialize(const char* type, size_t typeLen, | 
|  | SkEventSinkID targetID) { | 
|  | fType = NULL; | 
|  | setType(type, typeLen); | 
|  | f32 = 0; | 
|  | fTargetID = targetID; | 
|  | fTargetProc = NULL; | 
|  | #ifdef SK_DEBUG | 
|  | fTime = 0; | 
|  | fNextEvent = NULL; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | SkEvent::SkEvent() | 
|  | { | 
|  | initialize("", 0, 0); | 
|  | } | 
|  |  | 
|  | SkEvent::SkEvent(const SkEvent& src) | 
|  | { | 
|  | *this = src; | 
|  | if (((size_t) fType & 1) == 0) | 
|  | setType(src.fType); | 
|  | } | 
|  |  | 
|  | SkEvent::SkEvent(const SkString& type, SkEventSinkID targetID) | 
|  | { | 
|  | initialize(type.c_str(), type.size(), targetID); | 
|  | } | 
|  |  | 
|  | SkEvent::SkEvent(const char type[], SkEventSinkID targetID) | 
|  | { | 
|  | SkASSERT(type); | 
|  | initialize(type, strlen(type), targetID); | 
|  | } | 
|  |  | 
|  | SkEvent::~SkEvent() | 
|  | { | 
|  | if (((size_t) fType & 1) == 0) | 
|  | sk_free((void*) fType); | 
|  | } | 
|  |  | 
|  | static size_t makeCharArray(char* buffer, size_t compact) | 
|  | { | 
|  | size_t bits = (size_t) compact >> 1; | 
|  | memcpy(buffer, &bits, sizeof(compact)); | 
|  | buffer[sizeof(compact)] = 0; | 
|  | return strlen(buffer); | 
|  | } | 
|  |  | 
|  | void SkEvent::getType(SkString* str) const | 
|  | { | 
|  | if (str) | 
|  | { | 
|  | if ((size_t) fType & 1) // not a pointer | 
|  | { | 
|  | char chars[sizeof(size_t) + 1]; | 
|  | size_t len = makeCharArray(chars, (size_t) fType); | 
|  | str->set(chars, len); | 
|  | } | 
|  | else | 
|  | str->set(fType); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool SkEvent::isType(const SkString& str) const | 
|  | { | 
|  | return this->isType(str.c_str(), str.size()); | 
|  | } | 
|  |  | 
|  | bool SkEvent::isType(const char type[], size_t typeLen) const | 
|  | { | 
|  | if (typeLen == 0) | 
|  | typeLen = strlen(type); | 
|  | if ((size_t) fType & 1) {   // not a pointer | 
|  | char chars[sizeof(size_t) + 1]; | 
|  | size_t len = makeCharArray(chars, (size_t) fType); | 
|  | return len == typeLen && strncmp(chars, type, typeLen) == 0; | 
|  | } | 
|  | return strncmp(fType, type, typeLen) == 0 && fType[typeLen] == 0; | 
|  | } | 
|  |  | 
|  | void SkEvent::setType(const char type[], size_t typeLen) | 
|  | { | 
|  | if (typeLen == 0) | 
|  | typeLen = strlen(type); | 
|  | if (typeLen <= sizeof(fType)) { | 
|  | size_t slot = 0; | 
|  | memcpy(&slot, type, typeLen); | 
|  | if (slot << 1 >> 1 != slot) | 
|  | goto useCharStar; | 
|  | slot <<= 1; | 
|  | slot |= 1; | 
|  | fType = (char*) slot; | 
|  | } else { | 
|  | useCharStar: | 
|  | fType = (char*) sk_malloc_throw(typeLen + 1); | 
|  | SkASSERT(((size_t) fType & 1) == 0); | 
|  | memcpy(fType, type, typeLen); | 
|  | fType[typeLen] = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | void SkEvent::setType(const SkString& type) | 
|  | { | 
|  | setType(type.c_str()); | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | #include "SkParse.h" | 
|  |  | 
|  | void SkEvent::inflate(const SkDOM& dom, const SkDOM::Node* node) | 
|  | { | 
|  | const char* name = dom.findAttr(node, "type"); | 
|  | if (name) | 
|  | this->setType(name); | 
|  |  | 
|  | const char* value; | 
|  | if ((value = dom.findAttr(node, "fast32")) != NULL) | 
|  | { | 
|  | int32_t n; | 
|  | if (SkParse::FindS32(value, &n)) | 
|  | this->setFast32(n); | 
|  | } | 
|  |  | 
|  | for (node = dom.getFirstChild(node); node; node = dom.getNextSibling(node)) | 
|  | { | 
|  | if (strcmp(dom.getName(node), "data")) | 
|  | { | 
|  | SkDEBUGCODE(SkDebugf("SkEvent::inflate unrecognized subelement <%s>\n", dom.getName(node));) | 
|  | continue; | 
|  | } | 
|  |  | 
|  | name = dom.findAttr(node, "name"); | 
|  | if (name == NULL) | 
|  | { | 
|  | SkDEBUGCODE(SkDebugf("SkEvent::inflate missing required \"name\" attribute in <data> subelement\n");) | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if ((value = dom.findAttr(node, "s32")) != NULL) | 
|  | { | 
|  | int32_t n; | 
|  | if (SkParse::FindS32(value, &n)) | 
|  | this->setS32(name, n); | 
|  | } | 
|  | else if ((value = dom.findAttr(node, "scalar")) != NULL) | 
|  | { | 
|  | SkScalar x; | 
|  | if (SkParse::FindScalar(value, &x)) | 
|  | this->setScalar(name, x); | 
|  | } | 
|  | else if ((value = dom.findAttr(node, "string")) != NULL) | 
|  | this->setString(name, value); | 
|  | #ifdef SK_DEBUG | 
|  | else | 
|  | { | 
|  | SkDebugf("SkEvent::inflate <data name=\"%s\"> subelement missing required type attribute [S32 | scalar | string]\n", name); | 
|  | } | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | #ifdef SK_DEBUG | 
|  |  | 
|  | #ifndef SkScalarToFloat | 
|  | #define SkScalarToFloat(x)  ((x) / 65536.f) | 
|  | #endif | 
|  |  | 
|  | void SkEvent::dump(const char title[]) | 
|  | { | 
|  | if (title) | 
|  | SkDebugf("%s ", title); | 
|  |  | 
|  | SkString    etype; | 
|  | this->getType(&etype); | 
|  | SkDebugf("event<%s> fast32=%d", etype.c_str(), this->getFast32()); | 
|  |  | 
|  | const SkMetaData&   md = this->getMetaData(); | 
|  | SkMetaData::Iter    iter(md); | 
|  | SkMetaData::Type    mtype; | 
|  | int                 count; | 
|  | const char*         name; | 
|  |  | 
|  | while ((name = iter.next(&mtype, &count)) != NULL) | 
|  | { | 
|  | SkASSERT(count > 0); | 
|  |  | 
|  | SkDebugf(" <%s>=", name); | 
|  | switch (mtype) { | 
|  | case SkMetaData::kS32_Type:     // vector version??? | 
|  | { | 
|  | int32_t value; | 
|  | md.findS32(name, &value); | 
|  | SkDebugf("%d ", value); | 
|  | } | 
|  | break; | 
|  | case SkMetaData::kScalar_Type: | 
|  | { | 
|  | const SkScalar* values = md.findScalars(name, &count, NULL); | 
|  | SkDebugf("%f", SkScalarToFloat(values[0])); | 
|  | for (int i = 1; i < count; i++) | 
|  | SkDebugf(", %f", SkScalarToFloat(values[i])); | 
|  | SkDebugf(" "); | 
|  | } | 
|  | break; | 
|  | case SkMetaData::kString_Type: | 
|  | { | 
|  | const char* value = md.findString(name); | 
|  | SkASSERT(value); | 
|  | SkDebugf("<%s> ", value); | 
|  | } | 
|  | break; | 
|  | case SkMetaData::kPtr_Type:     // vector version??? | 
|  | { | 
|  | void*   value; | 
|  | md.findPtr(name, &value); | 
|  | SkDebugf("%p ", value); | 
|  | } | 
|  | break; | 
|  | case SkMetaData::kBool_Type:    // vector version??? | 
|  | { | 
|  | bool    value; | 
|  | md.findBool(name, &value); | 
|  | SkDebugf("%s ", value ? "true" : "false"); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | SkDEBUGFAIL("unknown metadata type returned from iterator"); | 
|  | break; | 
|  | } | 
|  | } | 
|  | SkDebugf("\n"); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | #ifdef SK_DEBUG | 
|  | // #define SK_TRACE_EVENTSx | 
|  | #endif | 
|  |  | 
|  | #ifdef SK_TRACE_EVENTS | 
|  | static void event_log(const char s[]) | 
|  | { | 
|  | SkDEBUGF(("%s\n", s)); | 
|  | } | 
|  |  | 
|  | #define EVENT_LOG(s)        event_log(s) | 
|  | #define EVENT_LOGN(s, n)    do { SkString str(s); str.append(" "); str.appendS32(n); event_log(str.c_str()); } while (0) | 
|  | #else | 
|  | #define EVENT_LOG(s) | 
|  | #define EVENT_LOGN(s, n) | 
|  | #endif | 
|  |  | 
|  | #include "SkThread.h" | 
|  | #include "SkTime.h" | 
|  |  | 
|  | class SkEvent_Globals { | 
|  | public: | 
|  | SkEvent_Globals() { | 
|  | fEventQHead = NULL; | 
|  | fEventQTail = NULL; | 
|  | fDelayQHead = NULL; | 
|  | SkDEBUGCODE(fEventCounter = 0;) | 
|  | } | 
|  |  | 
|  | SkMutex     fEventMutex; | 
|  | SkEvent*    fEventQHead, *fEventQTail; | 
|  | SkEvent*    fDelayQHead; | 
|  | SkDEBUGCODE(int fEventCounter;) | 
|  | }; | 
|  |  | 
|  | static SkEvent_Globals& getGlobals() { | 
|  | // leak this, so we don't incure any shutdown perf hit | 
|  | static SkEvent_Globals* gGlobals = new SkEvent_Globals; | 
|  | return *gGlobals; | 
|  | } | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | void SkEvent::postDelay(SkMSec delay) { | 
|  | if (!fTargetID && !fTargetProc) { | 
|  | delete this; | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (delay) { | 
|  | this->postTime(SkTime::GetMSecs() + delay); | 
|  | return; | 
|  | } | 
|  |  | 
|  | SkEvent_Globals& globals = getGlobals(); | 
|  |  | 
|  | globals.fEventMutex.acquire(); | 
|  | bool wasEmpty = SkEvent::Enqueue(this); | 
|  | globals.fEventMutex.release(); | 
|  |  | 
|  | // call outside of us holding the mutex | 
|  | if (wasEmpty) { | 
|  | SkEvent::SignalNonEmptyQueue(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SkEvent::postTime(SkMSec time) { | 
|  | if (!fTargetID && !fTargetProc) { | 
|  | delete this; | 
|  | return; | 
|  | } | 
|  |  | 
|  | SkEvent_Globals& globals = getGlobals(); | 
|  |  | 
|  | globals.fEventMutex.acquire(); | 
|  | SkMSec queueDelay = SkEvent::EnqueueTime(this, time); | 
|  | globals.fEventMutex.release(); | 
|  |  | 
|  | // call outside of us holding the mutex | 
|  | if ((int32_t)queueDelay != ~0) { | 
|  | SkEvent::SignalQueueTimer(queueDelay); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool SkEvent::Enqueue(SkEvent* evt) { | 
|  | SkEvent_Globals& globals = getGlobals(); | 
|  | //  gEventMutex acquired by caller | 
|  |  | 
|  | SkASSERT(evt); | 
|  |  | 
|  | bool wasEmpty = globals.fEventQHead == NULL; | 
|  |  | 
|  | if (globals.fEventQTail) | 
|  | globals.fEventQTail->fNextEvent = evt; | 
|  | globals.fEventQTail = evt; | 
|  | if (globals.fEventQHead == NULL) | 
|  | globals.fEventQHead = evt; | 
|  | evt->fNextEvent = NULL; | 
|  |  | 
|  | SkDEBUGCODE(++globals.fEventCounter); | 
|  |  | 
|  | return wasEmpty; | 
|  | } | 
|  |  | 
|  | SkEvent* SkEvent::Dequeue() { | 
|  | SkEvent_Globals& globals = getGlobals(); | 
|  | globals.fEventMutex.acquire(); | 
|  |  | 
|  | SkEvent* evt = globals.fEventQHead; | 
|  | if (evt) { | 
|  | SkDEBUGCODE(--globals.fEventCounter); | 
|  |  | 
|  | globals.fEventQHead = evt->fNextEvent; | 
|  | if (globals.fEventQHead == NULL) { | 
|  | globals.fEventQTail = NULL; | 
|  | } | 
|  | } | 
|  | globals.fEventMutex.release(); | 
|  |  | 
|  | return evt; | 
|  | } | 
|  |  | 
|  | bool SkEvent::QHasEvents() { | 
|  | SkEvent_Globals& globals = getGlobals(); | 
|  |  | 
|  | // this is not thread accurate, need a semaphore for that | 
|  | return globals.fEventQHead != NULL; | 
|  | } | 
|  |  | 
|  | #ifdef SK_TRACE_EVENTS | 
|  | static int gDelayDepth; | 
|  | #endif | 
|  |  | 
|  | SkMSec SkEvent::EnqueueTime(SkEvent* evt, SkMSec time) { | 
|  | SkEvent_Globals& globals = getGlobals(); | 
|  | //  gEventMutex acquired by caller | 
|  |  | 
|  | SkEvent* curr = globals.fDelayQHead; | 
|  | SkEvent* prev = NULL; | 
|  |  | 
|  | while (curr) { | 
|  | if (SkMSec_LT(time, curr->fTime)) { | 
|  | break; | 
|  | } | 
|  | prev = curr; | 
|  | curr = curr->fNextEvent; | 
|  | } | 
|  |  | 
|  | evt->fTime = time; | 
|  | evt->fNextEvent = curr; | 
|  | if (prev == NULL) { | 
|  | globals.fDelayQHead = evt; | 
|  | } else { | 
|  | prev->fNextEvent = evt; | 
|  | } | 
|  |  | 
|  | SkMSec delay = globals.fDelayQHead->fTime - SkTime::GetMSecs(); | 
|  | if ((int32_t)delay <= 0) { | 
|  | delay = 1; | 
|  | } | 
|  | return delay; | 
|  | } | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | #include "SkEventSink.h" | 
|  |  | 
|  | bool SkEvent::ProcessEvent() { | 
|  | SkEvent*                evt = SkEvent::Dequeue(); | 
|  | SkAutoTDelete<SkEvent>  autoDelete(evt); | 
|  | bool                    again = false; | 
|  |  | 
|  | EVENT_LOGN("ProcessEvent", (int32_t)evt); | 
|  |  | 
|  | if (evt) { | 
|  | (void)SkEventSink::DoEvent(*evt); | 
|  | again = SkEvent::QHasEvents(); | 
|  | } | 
|  | return again; | 
|  | } | 
|  |  | 
|  | void SkEvent::ServiceQueueTimer() | 
|  | { | 
|  | SkEvent_Globals& globals = getGlobals(); | 
|  |  | 
|  | globals.fEventMutex.acquire(); | 
|  |  | 
|  | bool        wasEmpty = false; | 
|  | SkMSec      now = SkTime::GetMSecs(); | 
|  | SkEvent*    evt = globals.fDelayQHead; | 
|  |  | 
|  | while (evt) | 
|  | { | 
|  | if (SkMSec_LT(now, evt->fTime)) | 
|  | break; | 
|  |  | 
|  | #ifdef SK_TRACE_EVENTS | 
|  | --gDelayDepth; | 
|  | SkDebugf("dequeue-delay %s (%d)", evt->getType(), gDelayDepth); | 
|  | const char* idStr = evt->findString("id"); | 
|  | if (idStr) | 
|  | SkDebugf(" (%s)", idStr); | 
|  | SkDebugf("\n"); | 
|  | #endif | 
|  |  | 
|  | SkEvent* next = evt->fNextEvent; | 
|  | if (SkEvent::Enqueue(evt)) | 
|  | wasEmpty = true; | 
|  | evt = next; | 
|  | } | 
|  | globals.fDelayQHead = evt; | 
|  |  | 
|  | SkMSec time = evt ? evt->fTime - now : 0; | 
|  |  | 
|  | globals.fEventMutex.release(); | 
|  |  | 
|  | if (wasEmpty) | 
|  | SkEvent::SignalNonEmptyQueue(); | 
|  |  | 
|  | SkEvent::SignalQueueTimer(time); | 
|  | } | 
|  |  | 
|  | int SkEvent::CountEventsOnQueue() { | 
|  | SkEvent_Globals& globals = getGlobals(); | 
|  | globals.fEventMutex.acquire(); | 
|  |  | 
|  | int count = 0; | 
|  | const SkEvent* evt = globals.fEventQHead; | 
|  | while (evt) { | 
|  | count += 1; | 
|  | evt = evt->fNextEvent; | 
|  | } | 
|  | globals.fEventMutex.release(); | 
|  |  | 
|  | return count; | 
|  | } | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | void SkEvent::Init() {} | 
|  |  | 
|  | void SkEvent::Term() { | 
|  | SkEvent_Globals& globals = getGlobals(); | 
|  |  | 
|  | SkEvent* evt = globals.fEventQHead; | 
|  | while (evt) { | 
|  | SkEvent* next = evt->fNextEvent; | 
|  | delete evt; | 
|  | evt = next; | 
|  | } | 
|  |  | 
|  | evt = globals.fDelayQHead; | 
|  | while (evt) { | 
|  | SkEvent* next = evt->fNextEvent; | 
|  | delete evt; | 
|  | evt = next; | 
|  | } | 
|  | } |