summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Noordhuis <pcnoordhuis@gmail.com>2010-12-28 20:49:18 +0100
committerPieter Noordhuis <pcnoordhuis@gmail.com>2010-12-28 20:49:18 +0100
commit8cb4d52cd273d6134f881c232a307c3259af334a (patch)
tree616a73c33dd0db660d263302dddb48d7ce1d19c5
parent29ea901b243265b209271775540d22701f337d57 (diff)
Run pending callbacks with a NULL reply on redisAsyncFree()
-rw-r--r--async.c53
1 files changed, 27 insertions, 26 deletions
diff --git a/async.c b/async.c
index e8f7931..91d6a8e 100644
--- a/async.c
+++ b/async.c
@@ -154,16 +154,29 @@ static int __redisShiftCallback(redisCallbackList *list, redisCallback *target)
/* Helper function to free the context. */
static void __redisAsyncFree(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
+ redisCallback cb;
- /* Clear callback list */
- while (__redisShiftCallback(&ac->replies,NULL) == REDIS_OK);
+ /* Execute pending callbacks with NULL reply. */
+ while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK) {
+ if (cb.fn != NULL) {
+ c->flags |= REDIS_IN_CALLBACK;
+ cb.fn(ac,NULL,cb.privdata);
+ c->flags &= ~REDIS_IN_CALLBACK;
+ }
+ }
/* Signal event lib to clean up */
if (ac->evCleanup) ac->evCleanup(ac->_adapter_data);
- /* Execute callback with proper status */
- if (ac->onDisconnect && (c->flags & REDIS_CONNECTED))
- ac->onDisconnect(ac, (ac->err == 0) ? REDIS_OK : REDIS_ERR);
+ /* Execute disconnect callback. When redisAsyncFree() initiated destroying
+ * this context, the status will always be REDIS_OK. */
+ if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) {
+ if (c->flags & REDIS_FREEING) {
+ ac->onDisconnect(ac,REDIS_OK);
+ } else {
+ ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR);
+ }
+ }
/* Cleanup self */
redisFree(c);
@@ -175,39 +188,29 @@ static void __redisAsyncFree(redisAsyncContext *ac) {
* redisProcessCallbacks(). Otherwise, the context is immediately free'd. */
void redisAsyncFree(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
- if (c->flags & REDIS_IN_CALLBACK) {
- c->flags |= REDIS_FREEING;
- } else {
+ c->flags |= REDIS_FREEING;
+ if (!(c->flags & REDIS_IN_CALLBACK))
__redisAsyncFree(ac);
- }
}
/* Helper function to make the disconnect happen and clean up. */
static void __redisAsyncDisconnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
- redisCallback cb;
/* Make sure error is accessible if there is any */
__redisAsyncCopyError(ac);
if (ac->err == 0) {
- /* When the connection is cleanly disconnected, there should not
- * be pending callbacks. */
+ /* For clean disconnects, there should be no pending callbacks. */
assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR);
} else {
- /* Callbacks should not be able to issue new commands. */
+ /* Disconnection is caused by an error, make sure that pending
+ * callbacks cannot call new commands. */
c->flags |= REDIS_DISCONNECTING;
-
- /* Execute pending callbacks with NULL reply. */
- while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK) {
- if (cb.fn != NULL) {
- c->flags |= REDIS_IN_CALLBACK;
- cb.fn(ac,NULL,cb.privdata);
- c->flags &= ~REDIS_IN_CALLBACK;
- }
- }
}
+ /* For non-clean disconnects, __redisAsyncFree() will execute pending
+ * callbacks with a NULL-reply. */
__redisAsyncFree(ac);
}
@@ -219,11 +222,9 @@ static void __redisAsyncDisconnect(redisAsyncContext *ac) {
* when there are no pending callbacks. */
void redisAsyncDisconnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
- if (c->flags & REDIS_IN_CALLBACK || ac->replies.head != NULL) {
- c->flags |= REDIS_DISCONNECTING;
- } else {
+ c->flags |= REDIS_DISCONNECTING;
+ if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL)
__redisAsyncDisconnect(ac);
- }
}
void redisProcessCallbacks(redisAsyncContext *ac) {