Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add timeout support for libuv adapter #1016

Merged
merged 9 commits into from
Jan 18, 2022

Conversation

MichaelSuen-thePointer
Copy link
Contributor

see #1015

sorry for no test cases : (

@michael-grunder michael-grunder self-assigned this Nov 17, 2021
@michael-grunder
Copy link
Collaborator

Thanks, looks good on first glance. I know it's somewhat trivial but would you mind re-indenting with 4 spaces?

Then I'll get it merged.

@MichaelSuen-thePointer
Copy link
Contributor Author

@michael-grunder
done :)

Copy link
Contributor

@zuiderkwast zuiderkwast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation looks fine. Didn't review the actual code. 🙈

@michael-grunder
Copy link
Collaborator

michael-grunder commented Dec 22, 2021

Hi, this code asserts when testing against the 0xDEADBEEF sentinel value.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <hiredis.h>
#include <async.h>
#include <adapters/libuv.h>
#include <time.h>
#include <sys/time.h>

void sleepCb(redisAsyncContext *c, void *r, void *privdata) {
    printf("sleep CB\n");
}

int main (int argc, char **argv) {
#ifndef _WIN32
    signal(SIGPIPE, SIG_IGN);
#endif

    uv_loop_t* loop = uv_default_loop();

    redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
    if (c->err) {
        /* Let *c leak for now... */
        printf("Error: %s\n", c->errstr);
        return 1;
    }

    redisLibuvAttach(c,loop);
    redisAsyncSetTimeout(c, (struct timeval){ .tv_sec = 1, .tv_usec = 0});
    redisAsyncCommand(c, sleepCb, NULL, "DEBUG SLEEP %f", 1.5);
    uv_run(loop, UV_RUN_DEFAULT);
    return 0;
}
$ ./uvtm
sleep CB
uvtm: /home/mike/dev/hiredis/adapters/libuv.h:83: on_handle_close: Assertion `p->timer.data == (void *)0xDEADBEEF' failed.

I'm wondering why we need the sentinel value at all

edit: I took a shot at adding a timeout to the libuv adapter and came up with this.

@MichaelSuen-thePointer
Copy link
Contributor Author

@michael-grunder
I was assuming the timer destroy callback to be earlier than the socket destroy callback, seems I was wrong. I will look into it soon.

edit: I took a shot at adding a timeout to the libuv adapter and came up with this.

I don't know if it is ok to just stop the timer and not 'destroy' it, but it should be good.

@MichaelSuen-thePointer
Copy link
Contributor Author

@michael-grunder
Ok fixed, now I use private data part of the uv handle as a guard to determine whether to call hi_free(p) or not. Now your example passed, and I added it to the example directory.

BTW, It is necessary to call uv_close on all of its handle type.

Copy link
Contributor

@bjosv bjosv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I have some suggestions.

Makefile Outdated
@@ -166,6 +166,8 @@ hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
hiredis-example-ssl: examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS)

hiredis-example-uvtm: examples/example-uvtm.c adapters/libuv.h $(STLIBNAME) $(SSL_STLIBNAME)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have an example for libuv some rows below. It might be better to put this new rule close to the existing one?
A suggestion is to rename this new example to something like hiredis-example-libuv-timeout to match the existing naming.
Maybe the existing one can be used for the timeout case?

#include <sys/time.h>

void sleepCb(redisAsyncContext *c, void *r, void *privdata) {
printf("sleep CB\n");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the async command timeout the reply should be NULL. This can be shown in this example by using

    redisReply *reply = r;
    assert(reply == NULL);

or by some simple printf.

@@ -0,0 +1,42 @@

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have an existing example-libuv.c, rename this to something like example-libuv-timeout.c?

Makefile Outdated
@@ -166,6 +166,8 @@ hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
hiredis-example-ssl: examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS)

hiredis-example-uvtm: examples/example-uvtm.c adapters/libuv.h $(STLIBNAME) $(SSL_STLIBNAME)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the example to the CMakeLists.txt in examples/ folder as well.
See how example-libuv is added and add a ADD_EXECUTABLE and TARGET_LINK_LIBRARIES to the new example.

printf("sleep CB\n");
}

int main (int argc, char **argv) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unused parameter argc and argv

#include <time.h>
#include <sys/time.h>

void sleepCb(redisAsyncContext *c, void *r, void *privdata) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unused parameter c, r, privdata

@MichaelSuen-thePointer
Copy link
Contributor Author

push -f to fix commit message, sorry
@bjosv I just merged example-uvtm with example-libuv and removed example-uvtm

adapters/libuv.h Outdated
}
// updates the timeout if the timer has already started
// or start the timer
uv_timer_start(&p->timer, (uv_timer_cb)redisLibuvTimeout, millsec, 0);
Copy link
Collaborator

@michael-grunder michael-grunder Jan 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Casting a function pointer in this way is undefined behavior and may crash in weird and hard to track down ways.

I'm not overly familiar with libuv but I'm guessing there is a way to #ifdef around it?

Edit: Looks like we can either use UV_VERSION at compile-time, or even uv_version() at runtime and then create a wrapper function with the int parameter that calls our real one without.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, it turns out I was using a very old libuv version (0.10.x), however I added the #ifdef and it is ok now.

adapters/libuv.h Outdated Show resolved Hide resolved
Co-authored-by: Michael Grunder <michael.grunder@gmail.com>
adapters/libuv.h Outdated
Comment on lines 93 to 94
#if UV_MAJOR_VERSION > 0 || UV_MINOR_VERSION > 11 || (defined(UV_VERSION_PATCH) && UV_VERSION_PATCH > 22)
#if !defined(UV_VERSION_PATCH) || (UV_MAJOR_VERSION < 1 && UV_MINOR_VERSION < 12 && UV_VERSION_PATCH < 23)
// libuv removed `status` parameter since v0.11.23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is maybe wrong for versions like 0.10.37 (it exists).

minor < 12 doesn't always mean minor == 11.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, thanks for the note, you are correct, major.minor.patch < 0.11.23 expands to something like major < 0 || (major == 0 && minor < 11) || (minor == 11 && patch < 23)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me try reduce it, could you lend some help?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major < 0 can't happen so this part can be removed.

I think major == 0 && (minor < 11 || (minor == 11 && patch < 23))

@MichaelSuen-thePointer
Copy link
Contributor Author

Fixed a silly typo, corrected version check macro, thanks @zuiderkwast for the help

adapters/libuv.h Outdated Show resolved Hide resolved
Co-authored-by: Viktor Söderqvist <viktor@zuiderkwast.se>
adapters/libuv.h Outdated Show resolved Hide resolved
@michael-grunder michael-grunder merged commit e73ab2f into redis:master Jan 18, 2022
@michael-grunder
Copy link
Collaborator

Merged, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants