Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
hiredis
Commits
31c91408
Commit
31c91408
authored
Mar 27, 2021
by
Kristján Valur Jónsson
Browse files
Polling adapter and example
parent
8a15f4d6
Changes
3
Show whitespace changes
Inline
Side-by-side
Makefile
View file @
31c91408
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
# This file is released under the BSD license, see the COPYING file
# This file is released under the BSD license, see the COPYING file
OBJ
=
alloc.o net.o hiredis.o sds.o async.o read.o sockcompat.o
OBJ
=
alloc.o net.o hiredis.o sds.o async.o read.o sockcompat.o
EXAMPLES
=
hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib hiredis-example-push
EXAMPLES
=
hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib hiredis-example-push
hiredis-example-poll
TESTS
=
hiredis-test
TESTS
=
hiredis-test
LIBNAME
=
libhiredis
LIBNAME
=
libhiredis
PKGCONFNAME
=
hiredis.pc
PKGCONFNAME
=
hiredis.pc
...
@@ -192,6 +192,9 @@ hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
...
@@ -192,6 +192,9 @@ hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
hiredis-example-ssl
:
examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME)
hiredis-example-ssl
:
examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME)
$(CC)
-o
examples/
$@
$(REAL_CFLAGS)
-I
.
$<
$(STLIBNAME)
$(SSL_STLIBNAME)
$(REAL_LDFLAGS)
$(SSL_LDFLAGS)
$(CC)
-o
examples/
$@
$(REAL_CFLAGS)
-I
.
$<
$(STLIBNAME)
$(SSL_STLIBNAME)
$(REAL_LDFLAGS)
$(SSL_LDFLAGS)
hiredis-example-poll
:
examples/example-poll.c adapters/poll.h $(STLIBNAME)
$(CC)
-o
examples/
$@
$(REAL_CFLAGS)
-I
.
$<
$(STLIBNAME)
$(REAL_LDFLAGS)
ifndef
AE_DIR
ifndef
AE_DIR
hiredis-example-ae
:
hiredis-example-ae
:
@
echo
"Please specify AE_DIR (e.g. <redis repository>/src)"
@
echo
"Please specify AE_DIR (e.g. <redis repository>/src)"
...
...
adapters/poll.h
0 → 100644
View file @
31c91408
#ifndef HIREDIS_POLL_H
#define HIREDIS_POLL_H
#include "../async.h"
#include "../sockcompat.h"
#include <string.h> // for memset
#include <errno.h>
/* Values to return from redisPollTick */
#define REDIS_POLL_HANDLED_READ 1
#define REDIS_POLL_HANDLED_WRITE 2
#define REDIS_POLL_HANDLED_TIMEOUT 4
/* An adapter to allow manual polling of the async context by checking the state
* of the underlying file descriptor. Useful in cases where there is no formal
* IO event loop but regular ticking can be used, such as in game engines. */
typedef
struct
redisPollEvents
{
redisAsyncContext
*
context
;
redisFD
fd
;
char
reading
,
writing
;
char
in_tick
;
char
deleted
;
double
deadline
;
}
redisPollEvents
;
static
double
redisPollTimevalToDouble
(
struct
timeval
*
tv
)
{
if
(
tv
==
NULL
)
return
0
.
0
;
return
tv
->
tv_sec
+
tv
->
tv_usec
/
1000000
.
00
;
}
static
double
redisPollGetNow
(
void
)
{
#ifndef _MSC_VER
struct
timeval
tv
;
gettimeofday
(
&
tv
,
NULL
);
return
redisPollTimevalToDouble
(
&
tv
);
#else
FILETIME
ft
;
ULARGE_INTEGER
li
;
GetSystemTimeAsFileTime
(
&
ft
);
li
.
HighPart
=
ft
.
dwHighDateTime
;
li
.
LowPart
=
ft
.
dwLowDateTime
;
return
(
double
)
li
.
QuadPart
*
1e-7
;
#endif
}
/* Poll for io, handling any pending callbacks. The timeout argument can be
* positive to wait for a maximum given time for IO, zero to poll, or negative
* to wait forever */
static
int
redisPollTick
(
redisAsyncContext
*
ac
,
double
timeout
)
{
int
reading
,
writing
;
struct
pollfd
pfd
;
int
handled
;
int
ns
;
int
itimeout
;
redisPollEvents
*
e
=
(
redisPollEvents
*
)
ac
->
ev
.
data
;
if
(
!
e
)
return
0
;
/* local flags, won't get changed during callbacks */
reading
=
e
->
reading
;
writing
=
e
->
writing
;
if
(
!
reading
&&
!
writing
)
return
0
;
pfd
.
fd
=
e
->
fd
;
pfd
.
events
=
0
;
if
(
reading
)
pfd
.
events
=
POLLIN
;
if
(
writing
)
pfd
.
events
|=
POLLOUT
;
if
(
timeout
>=
0
.
0
)
{
itimeout
=
(
int
)(
timeout
*
1000
.
0
);
}
else
{
itimeout
=
-
1
;
}
ns
=
poll
(
&
pfd
,
1
,
itimeout
);
if
(
ns
<
0
)
{
/* ignore the EINTR error */
if
(
errno
!=
EINTR
)
return
ns
;
ns
=
0
;
}
handled
=
0
;
e
->
in_tick
=
1
;
if
(
ns
)
{
if
(
reading
&&
(
pfd
.
revents
&
POLLIN
))
{
redisAsyncHandleRead
(
ac
);
handled
|=
REDIS_POLL_HANDLED_READ
;
}
/* on Windows, connection failure is indicated with the Exception fdset.
* handle it the same as writable. */
if
(
writing
&&
(
pfd
.
revents
&
(
POLLOUT
|
POLLERR
)))
{
/* context Read callback may have caused context to be deleted, e.g.
by doing an redisAsyncDisconnect() */
if
(
!
e
->
deleted
)
{
redisAsyncHandleWrite
(
ac
);
handled
|=
REDIS_POLL_HANDLED_WRITE
;
}
}
}
/* perform timeouts */
if
(
!
e
->
deleted
&&
e
->
deadline
!=
0
.
0
)
{
double
now
=
redisPollGetNow
();
if
(
now
>=
e
->
deadline
)
{
/* deadline has passed. disable timeout and perform callback */
e
->
deadline
=
0
.
0
;
redisAsyncHandleTimeout
(
ac
);
handled
|=
REDIS_POLL_HANDLED_TIMEOUT
;
}
}
/* do a delayed cleanup if required */
if
(
e
->
deleted
)
hi_free
(
e
);
else
e
->
in_tick
=
0
;
return
handled
;
}
static
void
redisPollAddRead
(
void
*
data
)
{
redisPollEvents
*
e
=
(
redisPollEvents
*
)
data
;
e
->
reading
=
1
;
}
static
void
redisPollDelRead
(
void
*
data
)
{
redisPollEvents
*
e
=
(
redisPollEvents
*
)
data
;
e
->
reading
=
0
;
}
static
void
redisPollAddWrite
(
void
*
data
)
{
redisPollEvents
*
e
=
(
redisPollEvents
*
)
data
;
e
->
writing
=
1
;
}
static
void
redisPollDelWrite
(
void
*
data
)
{
redisPollEvents
*
e
=
(
redisPollEvents
*
)
data
;
e
->
writing
=
0
;
}
static
void
redisPollCleanup
(
void
*
data
)
{
redisPollEvents
*
e
=
(
redisPollEvents
*
)
data
;
/* if we are currently processing a tick, postpone deletion */
if
(
e
->
in_tick
)
e
->
deleted
=
1
;
else
hi_free
(
e
);
}
static
void
redisPollScheduleTimer
(
void
*
data
,
struct
timeval
tv
)
{
redisPollEvents
*
e
=
(
redisPollEvents
*
)
data
;
double
now
=
redisPollGetNow
();
e
->
deadline
=
now
+
redisPollTimevalToDouble
(
&
tv
);
}
static
int
redisPollAttach
(
redisAsyncContext
*
ac
)
{
redisContext
*
c
=
&
(
ac
->
c
);
redisPollEvents
*
e
;
/* Nothing should be attached when something is already attached */
if
(
ac
->
ev
.
data
!=
NULL
)
return
REDIS_ERR
;
/* Create container for context and r/w events */
e
=
(
redisPollEvents
*
)
hi_malloc
(
sizeof
(
*
e
));
if
(
e
==
NULL
)
return
REDIS_ERR
;
memset
(
e
,
0
,
sizeof
(
*
e
));
e
->
context
=
ac
;
e
->
fd
=
c
->
fd
;
e
->
reading
=
e
->
writing
=
0
;
e
->
in_tick
=
e
->
deleted
=
0
;
e
->
deadline
=
0
.
0
;
/* Register functions to start/stop listening for events */
ac
->
ev
.
addRead
=
redisPollAddRead
;
ac
->
ev
.
delRead
=
redisPollDelRead
;
ac
->
ev
.
addWrite
=
redisPollAddWrite
;
ac
->
ev
.
delWrite
=
redisPollDelWrite
;
ac
->
ev
.
scheduleTimer
=
redisPollScheduleTimer
;
ac
->
ev
.
cleanup
=
redisPollCleanup
;
ac
->
ev
.
data
=
e
;
return
REDIS_OK
;
}
#endif
/* HIREDIS_POLL_H */
examples/example-poll.c
0 → 100644
View file @
31c91408
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <async.h>
#include <adapters/poll.h>
/* Put in the global scope, so that loop can be explicitly stopped */
static
int
exit_loop
=
0
;
void
getCallback
(
redisAsyncContext
*
c
,
void
*
r
,
void
*
privdata
)
{
redisReply
*
reply
=
r
;
if
(
reply
==
NULL
)
return
;
printf
(
"argv[%s]: %s
\n
"
,
(
char
*
)
privdata
,
reply
->
str
);
/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect
(
c
);
}
void
connectCallback
(
const
redisAsyncContext
*
c
,
int
status
)
{
if
(
status
!=
REDIS_OK
)
{
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
exit_loop
=
1
;
return
;
}
printf
(
"Connected...
\n
"
);
}
void
disconnectCallback
(
const
redisAsyncContext
*
c
,
int
status
)
{
exit_loop
=
1
;
if
(
status
!=
REDIS_OK
)
{
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
return
;
}
printf
(
"Disconnected...
\n
"
);
}
int
main
(
int
argc
,
char
**
argv
)
{
signal
(
SIGPIPE
,
SIG_IGN
);
redisAsyncContext
*
c
=
redisAsyncConnect
(
"127.0.0.1"
,
6379
);
if
(
c
->
err
)
{
/* Let *c leak for now... */
printf
(
"Error: %s
\n
"
,
c
->
errstr
);
return
1
;
}
redisPollAttach
(
c
);
redisAsyncSetConnectCallback
(
c
,
connectCallback
);
redisAsyncSetDisconnectCallback
(
c
,
disconnectCallback
);
redisAsyncCommand
(
c
,
NULL
,
NULL
,
"SET key %b"
,
argv
[
argc
-
1
],
strlen
(
argv
[
argc
-
1
]));
redisAsyncCommand
(
c
,
getCallback
,
(
char
*
)
"end-1"
,
"GET key"
);
while
(
!
exit_loop
)
{
redisPollTick
(
c
,
0
.
1
);
}
return
0
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment