diff options
Diffstat (limited to 'src/core/basetypes/MCObject.cc')
-rw-r--r-- | src/core/basetypes/MCObject.cc | 170 |
1 files changed, 136 insertions, 34 deletions
diff --git a/src/core/basetypes/MCObject.cc b/src/core/basetypes/MCObject.cc index 874e802d..9dcec15a 100644 --- a/src/core/basetypes/MCObject.cc +++ b/src/core/basetypes/MCObject.cc @@ -5,6 +5,7 @@ #include <cxxabi.h> #include <libetpan/libetpan.h> #include <string.h> +#include <Block.h> #include "MCAutoreleasePool.h" #include "MCString.h" @@ -139,11 +140,89 @@ static void initDelayedPerform() } struct mainThreadCallKeyData { + Object * dispatchQueueIdentifier; Object * obj; void * context; Object::Method method; }; +static void removeFromPerformHash(Object * obj, Object::Method method, void * context, void * targetDispatchQueue) +{ + chashdatum key; + struct mainThreadCallKeyData keyData; + Object * queueIdentifier = NULL; +#if __APPLE__ + queueIdentifier = (String *) dispatch_queue_get_specific((dispatch_queue_t) targetDispatchQueue, "MCDispatchQueueID"); +#endif + keyData.dispatchQueueIdentifier = queueIdentifier; + keyData.obj = obj; + keyData.context = context; + keyData.method = method; + key.data = &keyData; + key.len = sizeof(keyData); + + chash_delete(delayedPerformHash, (chashdatum *) &key, NULL); +} + +static void queueIdentifierDestructor(void * identifier) +{ + Object * obj = (Object *) identifier; + MC_SAFE_RELEASE(obj); +} + +static void addToPerformHash(Object * obj, Object::Method method, void * context, void * targetDispatchQueue, + void * performValue) +{ + chashdatum key; + chashdatum value; + struct mainThreadCallKeyData keyData; + Object * queueIdentifier = NULL; +#if __APPLE__ + queueIdentifier = (String *) dispatch_queue_get_specific((dispatch_queue_t) targetDispatchQueue, "MCDispatchQueueID"); + if (queueIdentifier == NULL) { + queueIdentifier = new Object(); + dispatch_queue_set_specific((dispatch_queue_t) targetDispatchQueue, "MCDispatchQueueID", queueIdentifier, queueIdentifierDestructor); + } +#endif + keyData.dispatchQueueIdentifier = queueIdentifier; + keyData.obj = obj; + keyData.context = context; + keyData.method = method; + key.data = &keyData; + key.len = sizeof(keyData); + value.data = performValue; + value.len = 0; + chash_set(delayedPerformHash, &key, &value, NULL); +} + +static void * getFromPerformHash(Object * obj, Object::Method method, void * context, void * targetDispatchQueue) +{ + chashdatum key; + chashdatum value; + struct mainThreadCallKeyData keyData; + int r; + + Object * queueIdentifier = NULL; +#if __APPLE__ + MCAssert(targetDispatchQueue != NULL); + queueIdentifier = (String *) dispatch_queue_get_specific((dispatch_queue_t) targetDispatchQueue, "MCDispatchQueueID"); + if (queueIdentifier == NULL) + return NULL; +#endif + keyData.dispatchQueueIdentifier = queueIdentifier; + keyData.obj = obj; + keyData.context = context; + keyData.method = method; + key.data = &keyData; + key.len = sizeof(keyData); + + r = chash_get(delayedPerformHash, &key, &value); + if (r < 0) + return NULL; + + return value.data; +} + static void performOnMainThread(void * info) { struct mainThreadCallData * data; @@ -173,15 +252,7 @@ static void performAfterDelay(void * info) context = data->context; method = data->method; - chashdatum key; - struct mainThreadCallKeyData keyData; - keyData.obj = obj; - keyData.context = context; - keyData.method = method; - key.data = &keyData; - key.len = sizeof(keyData); - chash_delete(delayedPerformHash, &key, NULL); - + removeFromPerformHash(obj, method, context, NULL); (obj->*method)(context); free(data); @@ -219,10 +290,57 @@ void Object::performMethodOnDispatchQueue(Method method, void * context, void * }); } } + +struct cancellableBlock { + void (^block)(void); + bool cancelled; +}; + +void Object::performMethodOnDispatchQueueAfterDelay(Method method, void * context, void * targetDispatchQueue, bool delay) +{ + initDelayedPerform(); + + __block bool cancelled = false; + + void (^cancelableBlock)(bool cancel) = ^(bool cancel) { + if (cancel) { + cancelled = true; + return; + } + if (!cancelled) { + (this->*method)(context); + } + }; + + void (^dupCancelableBlock)(bool cancel) = Block_copy(cancelableBlock); + + retain(); + addToPerformHash(this, method, context, targetDispatchQueue, (void *) dupCancelableBlock); + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)); + dispatch_after(popTime, (dispatch_queue_t) targetDispatchQueue, ^(void) { + removeFromPerformHash(this, method, context, targetDispatchQueue); + dupCancelableBlock(false); + Block_release(dupCancelableBlock); + release(); + }); +} + +void Object::cancelDelayedPerformMethodOnDispatchQueue(Method method, void * context, void * targetDispatchQueue) +{ + initDelayedPerform(); + void (^dupCancelableBlock)(bool cancel) = (void (^)(bool)) getFromPerformHash(this, method, context, targetDispatchQueue); + if (dupCancelableBlock == NULL) + return; + removeFromPerformHash(this, method, context, targetDispatchQueue); + dupCancelableBlock(true); +} #endif void Object::performMethodAfterDelay(Method method, void * context, double delay) { +#if __APPLE__ + performMethodOnDispatchQueueAfterDelay(method, context, dispatch_get_main_queue(), delay); +#else initDelayedPerform(); struct mainThreadCallData * data; @@ -232,41 +350,25 @@ void Object::performMethodAfterDelay(Method method, void * context, double delay data->context = context; data->method = method; data->caller = callAfterDelay(performAfterDelay, data, delay); - - chashdatum key; - chashdatum value; - struct mainThreadCallKeyData keyData; - keyData.obj = this; - keyData.context = context; - keyData.method = method; - key.data = &keyData; - key.len = sizeof(keyData); - value.data = (void *) data; - value.len = 0; - chash_set(delayedPerformHash, &key, &value, NULL); + addToPerformHash(this, method, context, NULL, data); +#endif } void Object::cancelDelayedPerformMethod(Method method, void * context) { +#if __APPLE__ + cancelDelayedPerformMethodOnDispatchQueue(method, context, dispatch_get_main_queue()); +#else initDelayedPerform(); - int r; - chashdatum key; - chashdatum value; - struct mainThreadCallKeyData keyData; - keyData.obj = this; - keyData.context = context; - keyData.method = method; - key.data = &keyData; - key.len = sizeof(keyData); - r = chash_get(delayedPerformHash, &key, &value); - if (r < 0) + struct mainThreadCallData * data = getFromPerformHash(this, method, context, NULL); + if (data == NULL) return; - chash_delete(delayedPerformHash, &key, NULL); - struct mainThreadCallData * data = (struct mainThreadCallData *) value.data; + removeFromPerformHash(this, method, context, NULL); cancelDelayedCall(data->caller); free(data); +#endif } HashMap * Object::serializable() |