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