diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/async/imap/MCIMAPAsyncConnection.cc | 17 | ||||
-rwxr-xr-x | src/async/imap/MCIMAPAsyncConnection.h | 1 | ||||
-rw-r--r-- | src/core/basetypes/MCObject.cc | 170 | ||||
-rw-r--r-- | src/core/basetypes/MCObject.h | 4 |
4 files changed, 156 insertions, 36 deletions
diff --git a/src/async/imap/MCIMAPAsyncConnection.cc b/src/async/imap/MCIMAPAsyncConnection.cc index 8403b3ed..64f95dfb 100755 --- a/src/async/imap/MCIMAPAsyncConnection.cc +++ b/src/async/imap/MCIMAPAsyncConnection.cc @@ -105,6 +105,7 @@ IMAPAsyncConnection::IMAPAsyncConnection() mInternalLogger = new IMAPConnectionLogger(this); mAutomaticConfigurationEnabled = true; mQueueRunning = false; + mScheduledAutomaticDisconnect = false; } IMAPAsyncConnection::~IMAPAsyncConnection() @@ -562,14 +563,28 @@ void IMAPAsyncConnection::tryAutomaticDisconnect() return; } - cancelDelayedPerformMethod((Object::Method) &IMAPAsyncConnection::tryAutomaticDisconnectAfterDelay, NULL); + bool scheduledAutomaticDisconnect = mScheduledAutomaticDisconnect; + if (scheduledAutomaticDisconnect) { + cancelDelayedPerformMethod((Object::Method) &IMAPAsyncConnection::tryAutomaticDisconnectAfterDelay, NULL); + } + + mOwner->retain(); + mScheduledAutomaticDisconnect = true; performMethodAfterDelay((Object::Method) &IMAPAsyncConnection::tryAutomaticDisconnectAfterDelay, NULL, 30); + + if (scheduledAutomaticDisconnect) { + mOwner->release(); + } } void IMAPAsyncConnection::tryAutomaticDisconnectAfterDelay(void * context) { + mScheduledAutomaticDisconnect = false; + IMAPOperation * op = disconnectOperation(); op->start(); + + mOwner->release(); } void IMAPAsyncConnection::queueStartRunning() diff --git a/src/async/imap/MCIMAPAsyncConnection.h b/src/async/imap/MCIMAPAsyncConnection.h index ef6893c8..2c2ee505 100755 --- a/src/async/imap/MCIMAPAsyncConnection.h +++ b/src/async/imap/MCIMAPAsyncConnection.h @@ -151,6 +151,7 @@ namespace mailcore { pthread_mutex_t mConnectionLoggerLock; bool mAutomaticConfigurationEnabled; bool mQueueRunning; + bool mScheduledAutomaticDisconnect; virtual void tryAutomaticDisconnectAfterDelay(void * context); virtual IMAPMessageRenderingOperation * renderingOperation(IMAPMessage * message, 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() diff --git a/src/core/basetypes/MCObject.h b/src/core/basetypes/MCObject.h index 0f3a769b..e3d74f52 100644 --- a/src/core/basetypes/MCObject.h +++ b/src/core/basetypes/MCObject.h @@ -43,10 +43,12 @@ namespace mailcore { typedef void (Object::*Method) (void *); virtual void performMethod(Method method, void * context); virtual void performMethodOnMainThread(Method method, void * context, bool waitUntilDone = false); + virtual void performMethodAfterDelay(Method method, void * context, double delay); #if __APPLE__ virtual void performMethodOnDispatchQueue(Method method, void * context, void * targetDispatchQueue, bool waitUntilDone = false); + virtual void performMethodOnDispatchQueueAfterDelay(Method method, void * context, void * targetDispatchQueue, bool delay); + virtual void cancelDelayedPerformMethodOnDispatchQueue(Method method, void * context, void * targetDispatchQueue); #endif - virtual void performMethodAfterDelay(Method method, void * context, double delay); virtual void cancelDelayedPerformMethod(Method method, void * context); // serialization utils |