Run pending callbacks with a NULL reply on redisAsyncFree()
This commit is contained in:
parent
29ea901b24
commit
8cb4d52cd2
49
async.c
49
async.c
@ -154,16 +154,29 @@ static int __redisShiftCallback(redisCallbackList *list, redisCallback *target)
|
|||||||
/* Helper function to free the context. */
|
/* Helper function to free the context. */
|
||||||
static void __redisAsyncFree(redisAsyncContext *ac) {
|
static void __redisAsyncFree(redisAsyncContext *ac) {
|
||||||
redisContext *c = &(ac->c);
|
redisContext *c = &(ac->c);
|
||||||
|
redisCallback cb;
|
||||||
|
|
||||||
/* Clear callback list */
|
/* Execute pending callbacks with NULL reply. */
|
||||||
while (__redisShiftCallback(&ac->replies,NULL) == REDIS_OK);
|
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 */
|
/* Signal event lib to clean up */
|
||||||
if (ac->evCleanup) ac->evCleanup(ac->_adapter_data);
|
if (ac->evCleanup) ac->evCleanup(ac->_adapter_data);
|
||||||
|
|
||||||
/* Execute callback with proper status */
|
/* Execute disconnect callback. When redisAsyncFree() initiated destroying
|
||||||
if (ac->onDisconnect && (c->flags & REDIS_CONNECTED))
|
* this context, the status will always be REDIS_OK. */
|
||||||
ac->onDisconnect(ac, (ac->err == 0) ? REDIS_OK : REDIS_ERR);
|
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 */
|
/* Cleanup self */
|
||||||
redisFree(c);
|
redisFree(c);
|
||||||
@ -175,39 +188,29 @@ static void __redisAsyncFree(redisAsyncContext *ac) {
|
|||||||
* redisProcessCallbacks(). Otherwise, the context is immediately free'd. */
|
* redisProcessCallbacks(). Otherwise, the context is immediately free'd. */
|
||||||
void redisAsyncFree(redisAsyncContext *ac) {
|
void redisAsyncFree(redisAsyncContext *ac) {
|
||||||
redisContext *c = &(ac->c);
|
redisContext *c = &(ac->c);
|
||||||
if (c->flags & REDIS_IN_CALLBACK) {
|
|
||||||
c->flags |= REDIS_FREEING;
|
c->flags |= REDIS_FREEING;
|
||||||
} else {
|
if (!(c->flags & REDIS_IN_CALLBACK))
|
||||||
__redisAsyncFree(ac);
|
__redisAsyncFree(ac);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function to make the disconnect happen and clean up. */
|
/* Helper function to make the disconnect happen and clean up. */
|
||||||
static void __redisAsyncDisconnect(redisAsyncContext *ac) {
|
static void __redisAsyncDisconnect(redisAsyncContext *ac) {
|
||||||
redisContext *c = &(ac->c);
|
redisContext *c = &(ac->c);
|
||||||
redisCallback cb;
|
|
||||||
|
|
||||||
/* Make sure error is accessible if there is any */
|
/* Make sure error is accessible if there is any */
|
||||||
__redisAsyncCopyError(ac);
|
__redisAsyncCopyError(ac);
|
||||||
|
|
||||||
if (ac->err == 0) {
|
if (ac->err == 0) {
|
||||||
/* When the connection is cleanly disconnected, there should not
|
/* For clean disconnects, there should be no pending callbacks. */
|
||||||
* be pending callbacks. */
|
|
||||||
assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR);
|
assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR);
|
||||||
} else {
|
} 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;
|
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);
|
__redisAsyncFree(ac);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,11 +222,9 @@ static void __redisAsyncDisconnect(redisAsyncContext *ac) {
|
|||||||
* when there are no pending callbacks. */
|
* when there are no pending callbacks. */
|
||||||
void redisAsyncDisconnect(redisAsyncContext *ac) {
|
void redisAsyncDisconnect(redisAsyncContext *ac) {
|
||||||
redisContext *c = &(ac->c);
|
redisContext *c = &(ac->c);
|
||||||
if (c->flags & REDIS_IN_CALLBACK || ac->replies.head != NULL) {
|
|
||||||
c->flags |= REDIS_DISCONNECTING;
|
c->flags |= REDIS_DISCONNECTING;
|
||||||
} else {
|
if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL)
|
||||||
__redisAsyncDisconnect(ac);
|
__redisAsyncDisconnect(ac);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void redisProcessCallbacks(redisAsyncContext *ac) {
|
void redisProcessCallbacks(redisAsyncContext *ac) {
|
||||||
|
Loading…
Reference in New Issue
Block a user