Commit 8ac7af1c authored by antirez's avatar antirez
Browse files

Fix ae.c when a timer finalizerProc adds an event.

While this feature is not used by Redis, ae.c implements the ability for
a timer to call a finalizer callback when an timer event is deleted.
This feature was bugged since the start, and because it was never used
we never noticed a problem. However Anthony LaTorre was using the same
library in order to implement a different system: he found a bug that he
describes as follows, and which he fixed with the patch in this commit,
sent me by private email:

    --- Anthony email ---

've found one bug in the current implementation of the timed events.
It's possible to lose track of a timed event if an event is added in
the finalizerProc of another event.

For example, suppose you start off with three timed events 1, 2, and
3. Then the linked list looks like:

3 -> 2 -> 1

Then, you run processTimeEvents and events 2 and 3 finish, so now the
list looks like:

-1 -> -1 -> 2

Now, on the next iteration of processTimeEvents it starts by deleting
the first event, an...
parent 674909f4
...@@ -219,7 +219,10 @@ long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, ...@@ -219,7 +219,10 @@ long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
te->timeProc = proc; te->timeProc = proc;
te->finalizerProc = finalizerProc; te->finalizerProc = finalizerProc;
te->clientData = clientData; te->clientData = clientData;
te->prev = NULL;
te->next = eventLoop->timeEventHead; te->next = eventLoop->timeEventHead;
if (te->next)
te->next->prev = te;
eventLoop->timeEventHead = te; eventLoop->timeEventHead = te;
return id; return id;
} }
...@@ -266,7 +269,7 @@ static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop) ...@@ -266,7 +269,7 @@ static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop)
/* Process time events */ /* Process time events */
static int processTimeEvents(aeEventLoop *eventLoop) { static int processTimeEvents(aeEventLoop *eventLoop) {
int processed = 0; int processed = 0;
aeTimeEvent *te, *prev; aeTimeEvent *te;
long long maxId; long long maxId;
time_t now = time(NULL); time_t now = time(NULL);
...@@ -287,7 +290,6 @@ static int processTimeEvents(aeEventLoop *eventLoop) { ...@@ -287,7 +290,6 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
} }
eventLoop->lastTime = now; eventLoop->lastTime = now;
prev = NULL;
te = eventLoop->timeEventHead; te = eventLoop->timeEventHead;
maxId = eventLoop->timeEventNextId-1; maxId = eventLoop->timeEventNextId-1;
while(te) { while(te) {
...@@ -297,10 +299,12 @@ static int processTimeEvents(aeEventLoop *eventLoop) { ...@@ -297,10 +299,12 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
/* Remove events scheduled for deletion. */ /* Remove events scheduled for deletion. */
if (te->id == AE_DELETED_EVENT_ID) { if (te->id == AE_DELETED_EVENT_ID) {
aeTimeEvent *next = te->next; aeTimeEvent *next = te->next;
if (prev == NULL) if (te->prev)
eventLoop->timeEventHead = te->next; te->prev->next = te->next;
else else
prev->next = te->next; eventLoop->timeEventHead = te->next;
if (te->next)
te->next->prev = te->prev;
if (te->finalizerProc) if (te->finalizerProc)
te->finalizerProc(eventLoop, te->clientData); te->finalizerProc(eventLoop, te->clientData);
zfree(te); zfree(te);
...@@ -332,7 +336,6 @@ static int processTimeEvents(aeEventLoop *eventLoop) { ...@@ -332,7 +336,6 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
te->id = AE_DELETED_EVENT_ID; te->id = AE_DELETED_EVENT_ID;
} }
} }
prev = te;
te = te->next; te = te->next;
} }
return processed; return processed;
......
...@@ -83,6 +83,7 @@ typedef struct aeTimeEvent { ...@@ -83,6 +83,7 @@ typedef struct aeTimeEvent {
aeTimeProc *timeProc; aeTimeProc *timeProc;
aeEventFinalizerProc *finalizerProc; aeEventFinalizerProc *finalizerProc;
void *clientData; void *clientData;
struct aeTimeEvent *prev;
struct aeTimeEvent *next; struct aeTimeEvent *next;
} aeTimeEvent; } aeTimeEvent;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment