summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPengfei Han <hpf.comail@gmail.com>2023-04-23 22:02:09 +0800
committerGitHub <noreply@github.com>2023-04-23 17:02:09 +0300
commite289798483f492a613f85454a6b51de2f22b41cc (patch)
tree9523e746e86774c9448a27d02be5bfbffa36fda8
parentf809e10fd8f9e210291d05e80f6d08e3ddc01ae7 (diff)
downloadredis-e289798483f492a613f85454a6b51de2f22b41cc.tar.gz
after calling aeSetDontWait from beforesleep, aeProcessEvent may be still wait once (#12068)
The code in aeProcessEvent was testing AE_DONT_WAIT flag at the wrong time. The flag is set by by beforeSleep, but was was tested before calling beforeSleep, which would result in aeProcessEvent waiting when it shouldn't have, impacting TLS's HasPendingData. Co-authored-by: Oran Agra <oran@redislabs.com>
-rw-r--r--src/ae.c49
1 files changed, 22 insertions, 27 deletions
diff --git a/src/ae.c b/src/ae.c
index 468859c06..1b6422b2d 100644
--- a/src/ae.c
+++ b/src/ae.c
@@ -103,7 +103,11 @@ int aeGetSetSize(aeEventLoop *eventLoop) {
return eventLoop->setsize;
}
-/* Tells the next iteration/s of the event processing to set timeout of 0. */
+/*
+ * Tell the event processing to change the wait timeout as soon as possible.
+ *
+ * Note: it just means you turn on/off the global AE_DONT_WAIT.
+ */
void aeSetDontWait(aeEventLoop *eventLoop, int noWait) {
if (noWait)
eventLoop->flags |= AE_DONT_WAIT;
@@ -361,44 +365,35 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags)
/* Nothing to do? return ASAP */
if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0;
- /* Note that we want to call select() even if there are no
+ /* Note that we want to call aeApiPoll() even if there are no
* file events to process as long as we want to process time
* events, in order to sleep until the next time event is ready
* to fire. */
if (eventLoop->maxfd != -1 ||
((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) {
int j;
- struct timeval tv, *tvp;
- int64_t usUntilTimer = -1;
+ struct timeval tv, *tvp = NULL; /* NULL means infinite wait. */
+ int64_t usUntilTimer;
- if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
- usUntilTimer = usUntilEarliestTimer(eventLoop);
+ if (eventLoop->beforesleep != NULL && (flags & AE_CALL_BEFORE_SLEEP))
+ eventLoop->beforesleep(eventLoop);
- if (usUntilTimer >= 0) {
- tv.tv_sec = usUntilTimer / 1000000;
- tv.tv_usec = usUntilTimer % 1000000;
+ /* The eventLoop->flags may be changed inside beforesleep.
+ * So we should check it after beforesleep be called. At the same time,
+ * the parameter flags always should have the highest priority.
+ * That is to say, once the parameter flag is set to AE_DONT_WAIT,
+ * no matter what value eventLoop->flags is set to, we should ignore it. */
+ if ((flags & AE_DONT_WAIT) || (eventLoop->flags & AE_DONT_WAIT)) {
+ tv.tv_sec = tv.tv_usec = 0;
tvp = &tv;
- } else {
- /* If we have to check for events but need to return
- * ASAP because of AE_DONT_WAIT we need to set the timeout
- * to zero */
- if (flags & AE_DONT_WAIT) {
- tv.tv_sec = tv.tv_usec = 0;
+ } else if (flags & AE_TIME_EVENTS) {
+ usUntilTimer = usUntilEarliestTimer(eventLoop);
+ if (usUntilTimer >= 0) {
+ tv.tv_sec = usUntilTimer / 1000000;
+ tv.tv_usec = usUntilTimer % 1000000;
tvp = &tv;
- } else {
- /* Otherwise we can block */
- tvp = NULL; /* wait forever */
}
}
-
- if (eventLoop->flags & AE_DONT_WAIT) {
- tv.tv_sec = tv.tv_usec = 0;
- tvp = &tv;
- }
-
- if (eventLoop->beforesleep != NULL && flags & AE_CALL_BEFORE_SLEEP)
- eventLoop->beforesleep(eventLoop);
-
/* Call the multiplexing API, will return only on timeout or when
* some event fires. */
numevents = aeApiPoll(eventLoop, tvp);