简介
在阅读https://github.com/microsoft/hiredis代码时,发现针对windows时平台iocp写时存在问题
分析
ae注册读写操作的添加删除处理回调
ac->ev.addRead = redisAeAddRead;
ac->ev.delRead = redisAeDelRead;
ac->ev.addWrite = redisAeAddWrite;
ac->ev.delWrite = redisAeDelWrite;
ac->ev.cleanup = redisAeCleanup;
ac->ev.data = e;
添加写操作时,会使用PostQueuedCompletionStatus
提交写请求
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
iocpSockState *sockstate = WSIOCP_GetSocketState(fd);
if (sockstate == NULL) {
errno = WSAEINVAL;
return -1;
}
if (mask & AE_READABLE) {
sockstate->masks |= AE_READABLE;
if ((sockstate->masks & CONNECT_PENDING) == 0) {
if (sockstate->masks & LISTEN_SOCK) {
// Actually a listen. Do not treat as read
} else {
if ((sockstate->masks & READ_QUEUED) == 0) {
// Queue up a 0 byte read
WSIOCP_QueueNextRead(fd);
}
}
}
}
if (mask & AE_WRITABLE) {
sockstate->masks |= AE_WRITABLE;
if ((sockstate->masks & CONNECT_PENDING) == 0) {
// If no write active, then need to queue write ready
if (sockstate->wreqs == 0) {
asendreq *areq = (asendreq *) CallocMemoryNoCOW(sizeof(asendreq));
aeApiState *state = (aeApiState *) eventLoop->apidata;
if (PostQueuedCompletionStatus(state->iocp,
0,
fd,
&areq->ov) == 0) {
errno = GetLastError();
FreeMemoryNoCOW(areq);
return -1;
}
sockstate->wreqs++;
listAddNodeTail(&sockstate->wreqlist, areq);
}
}
}
return 0;
}
当写事件回调时,会调用redisAeWriteEvent
static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
((void)el); ((void)fd); ((void)mask);
redisAeEvents *e = (redisAeEvents*)privdata;
redisAsyncHandleWrite(e->context);
}
void redisAsyncHandleWrite(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
int done = 0;
if (!(c->flags & REDIS_CONNECTED)) {
/* Abort connect was not successful. */
if (__redisAsyncHandleConnect(ac) != REDIS_OK)
return;
/* Try again later when the context is still not connected. */
if (!(c->flags & REDIS_CONNECTED))
return;
}
if (redisBufferWrite(c,&done) == REDIS_ERR) {
__redisAsyncDisconnect(ac);
} else {
/* Continue writing when not done, stop writing otherwise */
if (!done)
_EL_ADD_WRITE(ac);
else
_EL_DEL_WRITE(ac);
/* Always schedule reads after writes */
_EL_ADD_READ(ac);
}
}
如果写数据一次没有写完,即done为false时,此时_EL_ADD_WRITE
并不会再次触发写事件,因为此时e->writing
为1,写处理不会再次触发