Add session timer
This commit is contained in:
5
deps/timeout/CMakeLists.txt
vendored
5
deps/timeout/CMakeLists.txt
vendored
@@ -1,3 +1,2 @@
|
||||
set(CMAKE_C_FLAGS "-std=c99")
|
||||
add_definitions(-fPIC)
|
||||
add_library(timeout STATIC timeout.c timeout-bitops.c)
|
||||
add_library(timeout STATIC timeout.cpp timeout-bitops.cpp)
|
||||
target_include_directories(timeout PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <stdint.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h> /* _BitScanForward, _BitScanReverse */
|
||||
#include <intrin.h> /* _BitScanForward, _BitScanReverse */
|
||||
#endif
|
||||
|
||||
/* First define ctz and clz functions; these are compiler-dependent if
|
||||
@@ -54,14 +54,14 @@ static __inline int clz64(uint64_t val)
|
||||
#else
|
||||
static __inline int ctz64(uint64_t val)
|
||||
{
|
||||
uint32_t lo = (uint32_t) val;
|
||||
uint32_t hi = (uint32_t) (val >> 32);
|
||||
uint32_t lo = (uint32_t)val;
|
||||
uint32_t hi = (uint32_t)(val >> 32);
|
||||
return lo ? ctz32(lo) : 32 + ctz32(hi);
|
||||
}
|
||||
static __inline int clz64(uint64_t val)
|
||||
{
|
||||
uint32_t lo = (uint32_t) val;
|
||||
uint32_t hi = (uint32_t) (val >> 32);
|
||||
uint32_t lo = (uint32_t)val;
|
||||
uint32_t hi = (uint32_t)(val >> 32);
|
||||
return hi ? clz32(hi) : 32 + clz32(lo);
|
||||
}
|
||||
#endif
|
||||
@@ -72,9 +72,12 @@ static __inline int clz64(uint64_t val)
|
||||
|
||||
/* TODO: There are more clever ways to do this in the generic case. */
|
||||
|
||||
|
||||
#define process_(one, cz_bits, bits) \
|
||||
if (x < ( one << (cz_bits - bits))) { rv += bits; x <<= bits; }
|
||||
#define process_(one, cz_bits, bits) \
|
||||
if (x < (one << (cz_bits - bits))) \
|
||||
{ \
|
||||
rv += bits; \
|
||||
x <<= bits; \
|
||||
}
|
||||
|
||||
#define process64(bits) process_((UINT64_C(1)), 64, (bits))
|
||||
static inline int clz64(uint64_t x)
|
||||
@@ -105,8 +108,12 @@ static inline int clz32(uint32_t x)
|
||||
#undef process_
|
||||
#undef process32
|
||||
#undef process64
|
||||
#define process_(one, bits) \
|
||||
if ((x & ((one << (bits))-1)) == 0) { rv += bits; x >>= bits; }
|
||||
#define process_(one, bits) \
|
||||
if ((x & ((one << (bits)) - 1)) == 0) \
|
||||
{ \
|
||||
rv += bits; \
|
||||
x >>= bits; \
|
||||
}
|
||||
|
||||
#define process64(bits) process_((UINT64_C(1)), bits)
|
||||
static inline int ctz64(uint64_t x)
|
||||
@@ -152,15 +159,15 @@ static uint64_t testcases[] = {
|
||||
100,
|
||||
385789752,
|
||||
82574,
|
||||
(((uint64_t)1)<<63) + (((uint64_t)1)<<31) + 10101
|
||||
};
|
||||
(((uint64_t)1) << 63) + (((uint64_t)1) << 31) + 10101};
|
||||
|
||||
static int
|
||||
naive_clz(int bits, uint64_t v)
|
||||
{
|
||||
int r = 0;
|
||||
uint64_t bit = ((uint64_t)1) << (bits-1);
|
||||
while (bit && 0 == (v & bit)) {
|
||||
uint64_t bit = ((uint64_t)1) << (bits - 1);
|
||||
while (bit && 0 == (v & bit))
|
||||
{
|
||||
r++;
|
||||
bit >>= 1;
|
||||
}
|
||||
@@ -173,7 +180,8 @@ naive_ctz(int bits, uint64_t v)
|
||||
{
|
||||
int r = 0;
|
||||
uint64_t bit = 1;
|
||||
while (bit && 0 == (v & bit)) {
|
||||
while (bit && 0 == (v & bit))
|
||||
{
|
||||
r++;
|
||||
bit <<= 1;
|
||||
if (r == bits)
|
||||
@@ -186,46 +194,50 @@ naive_ctz(int bits, uint64_t v)
|
||||
static int
|
||||
check(uint64_t vv)
|
||||
{
|
||||
uint32_t v32 = (uint32_t) vv;
|
||||
uint32_t v32 = (uint32_t)vv;
|
||||
|
||||
if (vv == 0)
|
||||
return 1; /* c[tl]z64(0) is undefined. */
|
||||
|
||||
if (ctz64(vv) != naive_ctz(64, vv)) {
|
||||
if (ctz64(vv) != naive_ctz(64, vv))
|
||||
{
|
||||
printf("mismatch with ctz64: %d\n", ctz64(vv));
|
||||
exit(1);
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
if (clz64(vv) != naive_clz(64, vv)) {
|
||||
if (clz64(vv) != naive_clz(64, vv))
|
||||
{
|
||||
printf("mismatch with clz64: %d\n", clz64(vv));
|
||||
exit(1);
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v32 == 0)
|
||||
return 1; /* c[lt]z(0) is undefined. */
|
||||
|
||||
if (ctz32(v32) != naive_ctz(32, v32)) {
|
||||
if (ctz32(v32) != naive_ctz(32, v32))
|
||||
{
|
||||
printf("mismatch with ctz32: %d\n", ctz32(v32));
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
if (clz32(v32) != naive_clz(32, v32)) {
|
||||
if (clz32(v32) != naive_clz(32, v32))
|
||||
{
|
||||
printf("mismatch with clz32: %d\n", clz32(v32));
|
||||
exit(1);
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
main(int c, char **v)
|
||||
int main(int c, char **v)
|
||||
{
|
||||
unsigned int i;
|
||||
const unsigned int n = sizeof(testcases)/sizeof(testcases[0]);
|
||||
const unsigned int n = sizeof(testcases) / sizeof(testcases[0]);
|
||||
int result = 0;
|
||||
|
||||
for (i = 0; i <= 63; ++i) {
|
||||
for (i = 0; i <= 63; ++i)
|
||||
{
|
||||
uint64_t x = 1 << i;
|
||||
if (!check(x))
|
||||
result = 1;
|
||||
@@ -234,16 +246,19 @@ main(int c, char **v)
|
||||
result = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (! check(testcases[i]))
|
||||
for (i = 0; i < n; ++i)
|
||||
{
|
||||
if (!check(testcases[i]))
|
||||
result = 1;
|
||||
}
|
||||
if (result) {
|
||||
if (result)
|
||||
{
|
||||
puts("FAIL");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("OK");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
364
deps/timeout/timeout.c → deps/timeout/timeout.cpp
vendored
364
deps/timeout/timeout.c → deps/timeout/timeout.cpp
vendored
@@ -23,17 +23,17 @@
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* ==========================================================================
|
||||
*/
|
||||
#include <limits.h> /* CHAR_BIT */
|
||||
#include <limits.h> /* CHAR_BIT */
|
||||
|
||||
#include <stddef.h> /* NULL */
|
||||
#include <stdlib.h> /* malloc(3) free(3) */
|
||||
#include <stdio.h> /* FILE fprintf(3) */
|
||||
#include <stddef.h> /* NULL */
|
||||
#include <stdlib.h> /* malloc(3) free(3) */
|
||||
#include <stdio.h> /* FILE fprintf(3) */
|
||||
|
||||
#include <inttypes.h> /* UINT64_C uint64_t */
|
||||
#include <inttypes.h> /* UINT64_C uint64_t */
|
||||
|
||||
#include <string.h> /* memset(3) */
|
||||
#include <string.h> /* memset(3) */
|
||||
|
||||
#include <errno.h> /* errno */
|
||||
#include <errno.h> /* errno */
|
||||
|
||||
#include <sys/queue.h> /* TAILQ(3) */
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
#define reltime_t timeout_t /* "" */
|
||||
|
||||
#if !defined countof
|
||||
#define countof(a) (sizeof (a) / sizeof *(a))
|
||||
#define countof(a) (sizeof(a) / sizeof *(a))
|
||||
#endif
|
||||
|
||||
#if !defined endof
|
||||
@@ -66,32 +66,34 @@
|
||||
#endif
|
||||
|
||||
#if !defined MIN
|
||||
#define MIN(a, b) (((a) < (b))? (a) : (b))
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#if !defined MAX
|
||||
#define MAX(a, b) (((a) > (b))? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#if !defined TAILQ_CONCAT
|
||||
#define TAILQ_CONCAT(head1, head2, field) do { \
|
||||
if (!TAILQ_EMPTY(head2)) { \
|
||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
TAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (0)
|
||||
#define TAILQ_CONCAT(head1, head2, field) \
|
||||
do \
|
||||
{ \
|
||||
if (!TAILQ_EMPTY(head2)) \
|
||||
{ \
|
||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
TAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if !defined TAILQ_FOREACH_SAFE
|
||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = TAILQ_FIRST(head); \
|
||||
(var) && ((tvar) = TAILQ_NEXT(var, field), 1); \
|
||||
(var) = (tvar))
|
||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = TAILQ_FIRST(head); \
|
||||
(var) && ((tvar) = TAILQ_NEXT(var, field), 1); \
|
||||
(var) = (tvar))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* B I T M A N I P U L A T I O N R O U T I N E S
|
||||
*
|
||||
@@ -134,7 +136,7 @@
|
||||
#define WHEEL_MASK (WHEEL_LEN - 1)
|
||||
#define TIMEOUT_MAX ((TIMEOUT_C(1) << (WHEEL_BIT * WHEEL_NUM)) - 1)
|
||||
|
||||
#include "timeout-bitops.c"
|
||||
#include "timeout-bitops.cpp"
|
||||
|
||||
#if WHEEL_BIT == 6
|
||||
#define ctz(n) ctz64(n)
|
||||
@@ -181,23 +183,22 @@ typedef uint8_t wheel_t;
|
||||
#error invalid WHEEL_BIT value
|
||||
#endif
|
||||
|
||||
|
||||
static inline wheel_t rotl(const wheel_t v, int c) {
|
||||
static inline wheel_t rotl(const wheel_t v, int c)
|
||||
{
|
||||
if (!(c &= (sizeof v * CHAR_BIT - 1)))
|
||||
return v;
|
||||
|
||||
return (v << c) | (v >> (sizeof v * CHAR_BIT - c));
|
||||
} /* rotl() */
|
||||
|
||||
|
||||
static inline wheel_t rotr(const wheel_t v, int c) {
|
||||
static inline wheel_t rotr(const wheel_t v, int c)
|
||||
{
|
||||
if (!(c &= (sizeof v * CHAR_BIT - 1)))
|
||||
return v;
|
||||
|
||||
return (v >> c) | (v << (sizeof v * CHAR_BIT - c));
|
||||
} /* rotr() */
|
||||
|
||||
|
||||
/*
|
||||
* T I M E R R O U T I N E S
|
||||
*
|
||||
@@ -205,7 +206,8 @@ static inline wheel_t rotr(const wheel_t v, int c) {
|
||||
|
||||
TAILQ_HEAD(timeout_list, timeout);
|
||||
|
||||
struct timeouts {
|
||||
struct timeouts
|
||||
{
|
||||
struct timeout_list wheel[WHEEL_NUM][WHEEL_LEN], expired;
|
||||
|
||||
wheel_t pending[WHEEL_NUM];
|
||||
@@ -214,33 +216,36 @@ struct timeouts {
|
||||
timeout_t hertz;
|
||||
}; /* struct timeouts */
|
||||
|
||||
|
||||
static struct timeouts *timeouts_init(struct timeouts *T, timeout_t hz) {
|
||||
static struct timeouts *timeouts_init(struct timeouts *T, timeout_t hz)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0; i < countof(T->wheel); i++) {
|
||||
for (j = 0; j < countof(T->wheel[i]); j++) {
|
||||
for (i = 0; i < countof(T->wheel); i++)
|
||||
{
|
||||
for (j = 0; j < countof(T->wheel[i]); j++)
|
||||
{
|
||||
TAILQ_INIT(&T->wheel[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
TAILQ_INIT(&T->expired);
|
||||
|
||||
for (i = 0; i < countof(T->pending); i++) {
|
||||
for (i = 0; i < countof(T->pending); i++)
|
||||
{
|
||||
T->pending[i] = 0;
|
||||
}
|
||||
|
||||
T->curtime = 0;
|
||||
T->hertz = (hz)? hz : TIMEOUT_mHZ;
|
||||
T->hertz = (hz) ? hz : TIMEOUT_mHZ;
|
||||
|
||||
return T;
|
||||
} /* timeouts_init() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC struct timeouts *timeouts_open(timeout_t hz, int *error) {
|
||||
TIMEOUT_PUBLIC struct timeouts *timeouts_open(timeout_t hz, int *error)
|
||||
{
|
||||
struct timeouts *T;
|
||||
|
||||
if ((T = malloc(sizeof *T)))
|
||||
if ((T = (struct timeouts *)malloc(sizeof *T)))
|
||||
return timeouts_init(T, hz);
|
||||
|
||||
*error = errno;
|
||||
@@ -248,30 +253,33 @@ TIMEOUT_PUBLIC struct timeouts *timeouts_open(timeout_t hz, int *error) {
|
||||
return NULL;
|
||||
} /* timeouts_open() */
|
||||
|
||||
|
||||
static void timeouts_reset(struct timeouts *T) {
|
||||
static void timeouts_reset(struct timeouts *T)
|
||||
{
|
||||
struct timeout_list reset;
|
||||
struct timeout *to;
|
||||
unsigned i, j;
|
||||
|
||||
TAILQ_INIT(&reset);
|
||||
|
||||
for (i = 0; i < countof(T->wheel); i++) {
|
||||
for (j = 0; j < countof(T->wheel[i]); j++) {
|
||||
for (i = 0; i < countof(T->wheel); i++)
|
||||
{
|
||||
for (j = 0; j < countof(T->wheel[i]); j++)
|
||||
{
|
||||
TAILQ_CONCAT(&reset, &T->wheel[i][j], tqe);
|
||||
}
|
||||
}
|
||||
|
||||
TAILQ_CONCAT(&reset, &T->expired, tqe);
|
||||
|
||||
TAILQ_FOREACH(to, &reset, tqe) {
|
||||
TAILQ_FOREACH(to, &reset, tqe)
|
||||
{
|
||||
to->pending = NULL;
|
||||
TO_SET_TIMEOUTS(to, NULL);
|
||||
}
|
||||
} /* timeouts_reset() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC void timeouts_close(struct timeouts *T) {
|
||||
TIMEOUT_PUBLIC void timeouts_close(struct timeouts *T)
|
||||
{
|
||||
/*
|
||||
* NOTE: Delete installed timeouts so timeout_pending() and
|
||||
* timeout_expired() worked as expected.
|
||||
@@ -281,17 +289,19 @@ TIMEOUT_PUBLIC void timeouts_close(struct timeouts *T) {
|
||||
free(T);
|
||||
} /* timeouts_close() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC timeout_t timeouts_hz(struct timeouts *T) {
|
||||
TIMEOUT_PUBLIC timeout_t timeouts_hz(struct timeouts *T)
|
||||
{
|
||||
return T->hertz;
|
||||
} /* timeouts_hz() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC void timeouts_del(struct timeouts *T, struct timeout *to) {
|
||||
if (to->pending) {
|
||||
TIMEOUT_PUBLIC void timeouts_del(struct timeouts *T, struct timeout *to)
|
||||
{
|
||||
if (to->pending)
|
||||
{
|
||||
TAILQ_REMOVE(to->pending, to, tqe);
|
||||
|
||||
if (to->pending != &T->expired && TAILQ_EMPTY(to->pending)) {
|
||||
if (to->pending != &T->expired && TAILQ_EMPTY(to->pending))
|
||||
{
|
||||
ptrdiff_t index = to->pending - &T->wheel[0][0];
|
||||
int wheel = index / WHEEL_LEN;
|
||||
int slot = index % WHEEL_LEN;
|
||||
@@ -304,24 +314,24 @@ TIMEOUT_PUBLIC void timeouts_del(struct timeouts *T, struct timeout *to) {
|
||||
}
|
||||
} /* timeouts_del() */
|
||||
|
||||
|
||||
static inline reltime_t timeout_rem(struct timeouts *T, struct timeout *to) {
|
||||
static inline reltime_t timeout_rem(struct timeouts *T, struct timeout *to)
|
||||
{
|
||||
return to->expires - T->curtime;
|
||||
} /* timeout_rem() */
|
||||
|
||||
|
||||
static inline int timeout_wheel(timeout_t timeout) {
|
||||
static inline int timeout_wheel(timeout_t timeout)
|
||||
{
|
||||
/* must be called with timeout != 0, so fls input is nonzero */
|
||||
return (fls(MIN(timeout, TIMEOUT_MAX)) - 1) / WHEEL_BIT;
|
||||
} /* timeout_wheel() */
|
||||
|
||||
|
||||
static inline int timeout_slot(int wheel, timeout_t expires) {
|
||||
static inline int timeout_slot(int wheel, timeout_t expires)
|
||||
{
|
||||
return WHEEL_MASK & ((expires >> (wheel * WHEEL_BIT)) - !!wheel);
|
||||
} /* timeout_slot() */
|
||||
|
||||
|
||||
static void timeouts_sched(struct timeouts *T, struct timeout *to, timeout_t expires) {
|
||||
static void timeouts_sched(struct timeouts *T, struct timeout *to, timeout_t expires)
|
||||
{
|
||||
timeout_t rem;
|
||||
int wheel, slot;
|
||||
|
||||
@@ -331,7 +341,8 @@ static void timeouts_sched(struct timeouts *T, struct timeout *to, timeout_t exp
|
||||
|
||||
TO_SET_TIMEOUTS(to, T);
|
||||
|
||||
if (expires > T->curtime) {
|
||||
if (expires > T->curtime)
|
||||
{
|
||||
rem = timeout_rem(T, to);
|
||||
|
||||
/* rem is nonzero since:
|
||||
@@ -346,18 +357,21 @@ static void timeouts_sched(struct timeouts *T, struct timeout *to, timeout_t exp
|
||||
TAILQ_INSERT_TAIL(to->pending, to, tqe);
|
||||
|
||||
T->pending[wheel] |= WHEEL_C(1) << slot;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
to->pending = &T->expired;
|
||||
TAILQ_INSERT_TAIL(to->pending, to, tqe);
|
||||
}
|
||||
} /* timeouts_sched() */
|
||||
|
||||
|
||||
#ifndef TIMEOUT_DISABLE_INTERVALS
|
||||
static void timeouts_readd(struct timeouts *T, struct timeout *to) {
|
||||
static void timeouts_readd(struct timeouts *T, struct timeout *to)
|
||||
{
|
||||
to->expires += to->interval;
|
||||
|
||||
if (to->expires <= T->curtime) {
|
||||
if (to->expires <= T->curtime)
|
||||
{
|
||||
/* If we've missed the next firing of this timeout, reschedule
|
||||
* it to occur at the next multiple of its interval after
|
||||
* the last time that it fired.
|
||||
@@ -371,8 +385,8 @@ static void timeouts_readd(struct timeouts *T, struct timeout *to) {
|
||||
} /* timeouts_readd() */
|
||||
#endif
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC void timeouts_add(struct timeouts *T, struct timeout *to, timeout_t timeout) {
|
||||
TIMEOUT_PUBLIC void timeouts_add(struct timeouts *T, struct timeout *to, timeout_t timeout)
|
||||
{
|
||||
#ifndef TIMEOUT_DISABLE_INTERVALS
|
||||
if (to->flags & TIMEOUT_INT)
|
||||
to->interval = MAX(1, timeout);
|
||||
@@ -384,8 +398,8 @@ TIMEOUT_PUBLIC void timeouts_add(struct timeouts *T, struct timeout *to, timeout
|
||||
timeouts_sched(T, to, T->curtime + timeout);
|
||||
} /* timeouts_add() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) {
|
||||
TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime)
|
||||
{
|
||||
timeout_t elapsed = curtime - T->curtime;
|
||||
struct timeout_list todo;
|
||||
int wheel;
|
||||
@@ -396,7 +410,8 @@ TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) {
|
||||
* There's no avoiding looping over every wheel. It's best to keep
|
||||
* WHEEL_NUM smallish.
|
||||
*/
|
||||
for (wheel = 0; wheel < WHEEL_NUM; wheel++) {
|
||||
for (wheel = 0; wheel < WHEEL_NUM; wheel++)
|
||||
{
|
||||
wheel_t pending;
|
||||
|
||||
/*
|
||||
@@ -413,9 +428,12 @@ TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) {
|
||||
* If a wheel rolls over, force a tick of the next higher
|
||||
* wheel.
|
||||
*/
|
||||
if ((elapsed >> (wheel * WHEEL_BIT)) > WHEEL_MAX) {
|
||||
if ((elapsed >> (wheel * WHEEL_BIT)) > WHEEL_MAX)
|
||||
{
|
||||
pending = (wheel_t)~WHEEL_C(0);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
wheel_t _elapsed = WHEEL_MASK & (elapsed >> (wheel * WHEEL_BIT));
|
||||
int oslot, nslot;
|
||||
|
||||
@@ -432,7 +450,8 @@ TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) {
|
||||
pending |= WHEEL_C(1) << nslot;
|
||||
}
|
||||
|
||||
while (pending & T->pending[wheel]) {
|
||||
while (pending & T->pending[wheel])
|
||||
{
|
||||
/* ctz input cannot be zero: loop condition. */
|
||||
int slot = ctz(pending & T->pending[wheel]);
|
||||
TAILQ_CONCAT(&todo, &T->wheel[wheel][slot], tqe);
|
||||
@@ -448,7 +467,8 @@ TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) {
|
||||
|
||||
T->curtime = curtime;
|
||||
|
||||
while (!TAILQ_EMPTY(&todo)) {
|
||||
while (!TAILQ_EMPTY(&todo))
|
||||
{
|
||||
struct timeout *to = TAILQ_FIRST(&todo);
|
||||
|
||||
TAILQ_REMOVE(&todo, to, tqe);
|
||||
@@ -460,29 +480,29 @@ TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) {
|
||||
return;
|
||||
} /* timeouts_update() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC void timeouts_step(struct timeouts *T, reltime_t elapsed) {
|
||||
TIMEOUT_PUBLIC void timeouts_step(struct timeouts *T, reltime_t elapsed)
|
||||
{
|
||||
timeouts_update(T, T->curtime + elapsed);
|
||||
} /* timeouts_step() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC bool timeouts_pending(struct timeouts *T) {
|
||||
TIMEOUT_PUBLIC bool timeouts_pending(struct timeouts *T)
|
||||
{
|
||||
wheel_t pending = 0;
|
||||
int wheel;
|
||||
|
||||
for (wheel = 0; wheel < WHEEL_NUM; wheel++) {
|
||||
for (wheel = 0; wheel < WHEEL_NUM; wheel++)
|
||||
{
|
||||
pending |= T->pending[wheel];
|
||||
}
|
||||
|
||||
return !!pending;
|
||||
} /* timeouts_pending() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC bool timeouts_expired(struct timeouts *T) {
|
||||
TIMEOUT_PUBLIC bool timeouts_expired(struct timeouts *T)
|
||||
{
|
||||
return !TAILQ_EMPTY(&T->expired);
|
||||
} /* timeouts_expired() */
|
||||
|
||||
|
||||
/*
|
||||
* Calculate the interval before needing to process any timeouts pending on
|
||||
* any wheel.
|
||||
@@ -499,15 +519,18 @@ TIMEOUT_PUBLIC bool timeouts_expired(struct timeouts *T) {
|
||||
*
|
||||
* We should never return a timeout larger than the lowest actual timeout.
|
||||
*/
|
||||
static timeout_t timeouts_int(struct timeouts *T) {
|
||||
static timeout_t timeouts_int(struct timeouts *T)
|
||||
{
|
||||
timeout_t timeout = ~TIMEOUT_C(0), _timeout;
|
||||
timeout_t relmask;
|
||||
int wheel, slot;
|
||||
|
||||
relmask = 0;
|
||||
|
||||
for (wheel = 0; wheel < WHEEL_NUM; wheel++) {
|
||||
if (T->pending[wheel]) {
|
||||
for (wheel = 0; wheel < WHEEL_NUM; wheel++)
|
||||
{
|
||||
if (T->pending[wheel])
|
||||
{
|
||||
slot = WHEEL_MASK & (T->curtime >> (wheel * WHEEL_BIT));
|
||||
|
||||
/* ctz input cannot be zero: T->pending[wheel] is
|
||||
@@ -521,28 +544,29 @@ static timeout_t timeouts_int(struct timeouts *T) {
|
||||
timeout = MIN(_timeout, timeout);
|
||||
}
|
||||
|
||||
relmask <<= WHEEL_BIT;
|
||||
relmask <<= WHEEL_BIT;
|
||||
relmask |= WHEEL_MASK;
|
||||
}
|
||||
|
||||
return timeout;
|
||||
} /* timeouts_int() */
|
||||
|
||||
|
||||
/*
|
||||
* Calculate the interval our caller can wait before needing to process
|
||||
* events.
|
||||
*/
|
||||
TIMEOUT_PUBLIC timeout_t timeouts_timeout(struct timeouts *T) {
|
||||
TIMEOUT_PUBLIC timeout_t timeouts_timeout(struct timeouts *T)
|
||||
{
|
||||
if (!TAILQ_EMPTY(&T->expired))
|
||||
return 0;
|
||||
|
||||
return timeouts_int(T);
|
||||
} /* timeouts_timeout() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC struct timeout *timeouts_get(struct timeouts *T) {
|
||||
if (!TAILQ_EMPTY(&T->expired)) {
|
||||
TIMEOUT_PUBLIC struct timeout *timeouts_get(struct timeouts *T)
|
||||
{
|
||||
if (!TAILQ_EMPTY(&T->expired))
|
||||
{
|
||||
struct timeout *to = TAILQ_FIRST(&T->expired);
|
||||
|
||||
TAILQ_REMOVE(&T->expired, to, tqe);
|
||||
@@ -555,23 +579,28 @@ TIMEOUT_PUBLIC struct timeout *timeouts_get(struct timeouts *T) {
|
||||
#endif
|
||||
|
||||
return to;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} /* timeouts_get() */
|
||||
|
||||
|
||||
/*
|
||||
* Use dumb looping to locate the earliest timeout pending on the wheel so
|
||||
* our invariant assertions can check the result of our optimized code.
|
||||
*/
|
||||
static struct timeout *timeouts_min(struct timeouts *T) {
|
||||
static struct timeout *timeouts_min(struct timeouts *T)
|
||||
{
|
||||
struct timeout *to, *min = NULL;
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0; i < countof(T->wheel); i++) {
|
||||
for (j = 0; j < countof(T->wheel[i]); j++) {
|
||||
TAILQ_FOREACH(to, &T->wheel[i][j], tqe) {
|
||||
for (i = 0; i < countof(T->wheel); i++)
|
||||
{
|
||||
for (j = 0; j < countof(T->wheel[i]); j++)
|
||||
{
|
||||
TAILQ_FOREACH(to, &T->wheel[i][j], tqe)
|
||||
{
|
||||
if (!min || to->expires < min->expires)
|
||||
min = to;
|
||||
}
|
||||
@@ -581,28 +610,34 @@ static struct timeout *timeouts_min(struct timeouts *T) {
|
||||
return min;
|
||||
} /* timeouts_min() */
|
||||
|
||||
|
||||
/*
|
||||
* Check some basic algorithm invariants. If these invariants fail then
|
||||
* something is definitely broken.
|
||||
*/
|
||||
#define report(...) do { \
|
||||
if ((fp)) \
|
||||
fprintf(fp, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define report(...) \
|
||||
do \
|
||||
{ \
|
||||
if ((fp)) \
|
||||
fprintf(fp, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define check(expr, ...) do { \
|
||||
if (!(expr)) { \
|
||||
report(__VA_ARGS__); \
|
||||
return 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define check(expr, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (!(expr)) \
|
||||
{ \
|
||||
report(__VA_ARGS__); \
|
||||
return 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *T, FILE *fp) {
|
||||
TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *T, FILE *fp)
|
||||
{
|
||||
timeout_t timeout;
|
||||
struct timeout *to;
|
||||
|
||||
if ((to = timeouts_min(T))) {
|
||||
if ((to = timeouts_min(T)))
|
||||
{
|
||||
check(to->expires > T->curtime, "missed timeout (expires:%" TIMEOUT_PRIu " <= curtime:%" TIMEOUT_PRIu ")\n", to->expires, T->curtime);
|
||||
|
||||
timeout = timeouts_int(T);
|
||||
@@ -610,7 +645,9 @@ TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *T, FILE *fp) {
|
||||
|
||||
timeout = timeouts_timeout(T);
|
||||
check(timeout <= to->expires - T->curtime, "wrong soft timeout (soft:%" TIMEOUT_PRIu " > hard:%" TIMEOUT_PRIu ") (expires:%" TIMEOUT_PRIu "; curtime:%" TIMEOUT_PRIu ")\n", timeout, (to->expires - T->curtime), to->expires, T->curtime);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
timeout = timeouts_timeout(T);
|
||||
|
||||
if (!TAILQ_EMPTY(&T->expired))
|
||||
@@ -622,49 +659,65 @@ TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *T, FILE *fp) {
|
||||
return 1;
|
||||
} /* timeouts_check() */
|
||||
|
||||
#define ENTER \
|
||||
do \
|
||||
{ \
|
||||
static const int pc0 = __LINE__; \
|
||||
switch (pc0 + it->pc) \
|
||||
{ \
|
||||
case __LINE__: \
|
||||
(void)0
|
||||
|
||||
#define ENTER \
|
||||
do { \
|
||||
static const int pc0 = __LINE__; \
|
||||
switch (pc0 + it->pc) { \
|
||||
case __LINE__: (void)0
|
||||
|
||||
#define SAVE_AND_DO(do_statement) \
|
||||
do { \
|
||||
it->pc = __LINE__ - pc0; \
|
||||
do_statement; \
|
||||
case __LINE__: (void)0; \
|
||||
#define SAVE_AND_DO(do_statement) \
|
||||
do \
|
||||
{ \
|
||||
it->pc = __LINE__ - pc0; \
|
||||
do_statement; \
|
||||
case __LINE__: \
|
||||
(void)0; \
|
||||
} while (0)
|
||||
|
||||
#define YIELD(rv) \
|
||||
#define YIELD(rv) \
|
||||
SAVE_AND_DO(return (rv))
|
||||
|
||||
#define LEAVE \
|
||||
SAVE_AND_DO(break); \
|
||||
} \
|
||||
} while (0)
|
||||
#define LEAVE \
|
||||
SAVE_AND_DO(break); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *T, struct timeouts_it *it) {
|
||||
TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *T, struct timeouts_it *it)
|
||||
{
|
||||
struct timeout *to;
|
||||
|
||||
ENTER;
|
||||
|
||||
if (it->flags & TIMEOUTS_EXPIRED) {
|
||||
if (it->flags & TIMEOUTS_CLEAR) {
|
||||
while ((to = timeouts_get(T))) {
|
||||
if (it->flags & TIMEOUTS_EXPIRED)
|
||||
{
|
||||
if (it->flags & TIMEOUTS_CLEAR)
|
||||
{
|
||||
while ((to = timeouts_get(T)))
|
||||
{
|
||||
YIELD(to);
|
||||
}
|
||||
} else {
|
||||
TAILQ_FOREACH_SAFE(to, &T->expired, tqe, it->to) {
|
||||
}
|
||||
else
|
||||
{
|
||||
TAILQ_FOREACH_SAFE(to, &T->expired, tqe, it->to)
|
||||
{
|
||||
YIELD(to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (it->flags & TIMEOUTS_PENDING) {
|
||||
for (it->i = 0; it->i < countof(T->wheel); it->i++) {
|
||||
for (it->j = 0; it->j < countof(T->wheel[it->i]); it->j++) {
|
||||
TAILQ_FOREACH_SAFE(to, &T->wheel[it->i][it->j], tqe, it->to) {
|
||||
if (it->flags & TIMEOUTS_PENDING)
|
||||
{
|
||||
for (it->i = 0; it->i < countof(T->wheel); it->i++)
|
||||
{
|
||||
for (it->j = 0; it->j < countof(T->wheel[it->i]); it->j++)
|
||||
{
|
||||
TAILQ_FOREACH_SAFE(to, &T->wheel[it->i][it->j], tqe, it->to)
|
||||
{
|
||||
YIELD(to);
|
||||
}
|
||||
}
|
||||
@@ -681,13 +734,13 @@ TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *T, struct timeouts
|
||||
#undef SAVE_AND_DO
|
||||
#undef ENTER
|
||||
|
||||
|
||||
/*
|
||||
* T I M E O U T R O U T I N E S
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
TIMEOUT_PUBLIC struct timeout *timeout_init(struct timeout *to, int flags) {
|
||||
TIMEOUT_PUBLIC struct timeout *timeout_init(struct timeout *to, int flags)
|
||||
{
|
||||
memset(to, 0, sizeof *to);
|
||||
|
||||
to->flags = flags;
|
||||
@@ -695,50 +748,49 @@ TIMEOUT_PUBLIC struct timeout *timeout_init(struct timeout *to, int flags) {
|
||||
return to;
|
||||
} /* timeout_init() */
|
||||
|
||||
|
||||
#ifndef TIMEOUT_DISABLE_RELATIVE_ACCESS
|
||||
TIMEOUT_PUBLIC bool timeout_pending(struct timeout *to) {
|
||||
TIMEOUT_PUBLIC bool timeout_pending(struct timeout *to)
|
||||
{
|
||||
return to->pending && to->pending != &to->timeouts->expired;
|
||||
} /* timeout_pending() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC bool timeout_expired(struct timeout *to) {
|
||||
TIMEOUT_PUBLIC bool timeout_expired(struct timeout *to)
|
||||
{
|
||||
return to->pending && to->pending == &to->timeouts->expired;
|
||||
} /* timeout_expired() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC void timeout_del(struct timeout *to) {
|
||||
TIMEOUT_PUBLIC void timeout_del(struct timeout *to)
|
||||
{
|
||||
timeouts_del(to->timeouts, to);
|
||||
} /* timeout_del() */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* V E R S I O N I N T E R F A C E S
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
TIMEOUT_PUBLIC int timeout_version(void) {
|
||||
TIMEOUT_PUBLIC int timeout_version(void)
|
||||
{
|
||||
return TIMEOUT_VERSION;
|
||||
} /* timeout_version() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC const char *timeout_vendor(void) {
|
||||
TIMEOUT_PUBLIC const char *timeout_vendor(void)
|
||||
{
|
||||
return TIMEOUT_VENDOR;
|
||||
} /* timeout_version() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC int timeout_v_rel(void) {
|
||||
TIMEOUT_PUBLIC int timeout_v_rel(void)
|
||||
{
|
||||
return TIMEOUT_V_REL;
|
||||
} /* timeout_version() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC int timeout_v_abi(void) {
|
||||
TIMEOUT_PUBLIC int timeout_v_abi(void)
|
||||
{
|
||||
return TIMEOUT_V_ABI;
|
||||
} /* timeout_version() */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC int timeout_v_api(void) {
|
||||
TIMEOUT_PUBLIC int timeout_v_api(void)
|
||||
{
|
||||
return TIMEOUT_V_API;
|
||||
} /* timeout_version() */
|
||||
|
||||
67
deps/timeout/timeout.h
vendored
67
deps/timeout/timeout.h
vendored
@@ -26,13 +26,12 @@
|
||||
#ifndef TIMEOUT_H
|
||||
#define TIMEOUT_H
|
||||
|
||||
#include <stdbool.h> /* bool */
|
||||
#include <stdio.h> /* FILE */
|
||||
#include <stdbool.h> /* bool */
|
||||
#include <stdio.h> /* FILE */
|
||||
|
||||
#include <inttypes.h> /* PRIu64 PRIx64 PRIX64 uint64_t */
|
||||
|
||||
#include <sys/queue.h> /* TAILQ(3) */
|
||||
#include <inttypes.h> /* PRIu64 PRIx64 PRIX64 uint64_t */
|
||||
|
||||
#include <sys/queue.h> /* TAILQ(3) */
|
||||
|
||||
/*
|
||||
* V E R S I O N I N T E R F A C E S
|
||||
@@ -44,7 +43,7 @@
|
||||
#endif
|
||||
|
||||
#define TIMEOUT_VERSION TIMEOUT_V_REL
|
||||
#define TIMEOUT_VENDOR "william@25thandClement.com"
|
||||
#define TIMEOUT_VENDOR "william@25thandClement.com"
|
||||
|
||||
#define TIMEOUT_V_REL 0x20160226
|
||||
#define TIMEOUT_V_ABI 0x20160224
|
||||
@@ -60,7 +59,6 @@ TIMEOUT_PUBLIC int timeout_v_abi(void);
|
||||
|
||||
TIMEOUT_PUBLIC int timeout_v_api(void);
|
||||
|
||||
|
||||
/*
|
||||
* I N T E G E R T Y P E I N T E R F A C E S
|
||||
*
|
||||
@@ -79,7 +77,6 @@ typedef uint64_t timeout_t;
|
||||
|
||||
#define timeout_error_t int /* for documentation purposes */
|
||||
|
||||
|
||||
/*
|
||||
* C A L L B A C K I N T E R F A C E
|
||||
*
|
||||
@@ -89,7 +86,8 @@ typedef uint64_t timeout_t;
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef TIMEOUT_CB_OVERRIDE
|
||||
struct timeout_cb {
|
||||
struct timeout_cb
|
||||
{
|
||||
void (*fn)();
|
||||
void *arg;
|
||||
}; /* struct timeout_cb */
|
||||
@@ -105,14 +103,20 @@ struct timeout_cb {
|
||||
#endif
|
||||
#define TIMEOUT_ABS 0x02 /* treat timeout values as absolute */
|
||||
|
||||
#define TIMEOUT_INITIALIZER(flags) { (flags) }
|
||||
#define TIMEOUT_INITIALIZER(flags) \
|
||||
{ \
|
||||
(flags) \
|
||||
}
|
||||
|
||||
#define timeout_setcb(to, fn, arg) do { \
|
||||
(to)->callback.fn = (fn); \
|
||||
(to)->callback.arg = (arg); \
|
||||
} while (0)
|
||||
#define timeout_setcb(to, _fn, _arg) \
|
||||
do \
|
||||
{ \
|
||||
(to)->callback.fn = (_fn); \
|
||||
(to)->callback.arg = (_arg); \
|
||||
} while (0)
|
||||
|
||||
struct timeout {
|
||||
struct timeout
|
||||
{
|
||||
int flags;
|
||||
|
||||
timeout_t expires;
|
||||
@@ -121,7 +125,8 @@ struct timeout {
|
||||
struct timeout_list *pending;
|
||||
/* timeout list if pending on wheel or expiry queue */
|
||||
|
||||
TAILQ_ENTRY(timeout) tqe;
|
||||
TAILQ_ENTRY(timeout)
|
||||
tqe;
|
||||
/* entry member for struct timeout_list lists */
|
||||
|
||||
#ifndef TIMEOUT_DISABLE_CALLBACKS
|
||||
@@ -140,14 +145,13 @@ struct timeout {
|
||||
#endif
|
||||
}; /* struct timeout */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC struct timeout *timeout_init(struct timeout *, int);
|
||||
/* initialize timeout structure (same as TIMEOUT_INITIALIZER) */
|
||||
|
||||
#ifndef TIMEOUT_DISABLE_RELATIVE_ACCESS
|
||||
TIMEOUT_PUBLIC bool timeout_pending(struct timeout *);
|
||||
/* true if on timing wheel, false otherwise */
|
||||
|
||||
|
||||
TIMEOUT_PUBLIC bool timeout_expired(struct timeout *);
|
||||
/* true if on expired queue, false otherwise */
|
||||
|
||||
@@ -200,17 +204,23 @@ TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *, FILE *);
|
||||
|
||||
#define TIMEOUTS_PENDING 0x10
|
||||
#define TIMEOUTS_EXPIRED 0x20
|
||||
#define TIMEOUTS_ALL (TIMEOUTS_PENDING|TIMEOUTS_EXPIRED)
|
||||
#define TIMEOUTS_CLEAR 0x40
|
||||
#define TIMEOUTS_ALL (TIMEOUTS_PENDING | TIMEOUTS_EXPIRED)
|
||||
#define TIMEOUTS_CLEAR 0x40
|
||||
|
||||
#define TIMEOUTS_IT_INITIALIZER(flags) { (flags), 0, 0, 0, 0 }
|
||||
#define TIMEOUTS_IT_INITIALIZER(flags) \
|
||||
{ \
|
||||
(flags), 0, 0, 0, 0 \
|
||||
}
|
||||
|
||||
#define TIMEOUTS_IT_INIT(cur, _flags) do { \
|
||||
(cur)->flags = (_flags); \
|
||||
(cur)->pc = 0; \
|
||||
} while (0)
|
||||
#define TIMEOUTS_IT_INIT(cur, _flags) \
|
||||
do \
|
||||
{ \
|
||||
(cur)->flags = (_flags); \
|
||||
(cur)->pc = 0; \
|
||||
} while (0)
|
||||
|
||||
struct timeouts_it {
|
||||
struct timeouts_it
|
||||
{
|
||||
int flags;
|
||||
unsigned pc, i, j;
|
||||
struct timeout *to;
|
||||
@@ -223,11 +233,10 @@ TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *, struct timeouts_
|
||||
* could invalidate cursor state and trigger a use-after-free.
|
||||
*/
|
||||
|
||||
#define TIMEOUTS_FOREACH(var, T, flags) \
|
||||
struct timeouts_it _it = TIMEOUTS_IT_INITIALIZER((flags)); \
|
||||
#define TIMEOUTS_FOREACH(var, T, flags) \
|
||||
struct timeouts_it _it = TIMEOUTS_IT_INITIALIZER((flags)); \
|
||||
while (((var) = timeouts_next((T), &_it)))
|
||||
|
||||
|
||||
/*
|
||||
* B O N U S W H E E L I N T E R F A C E S
|
||||
*
|
||||
|
||||
@@ -6,11 +6,13 @@ add_library(session_manager
|
||||
session.cpp
|
||||
session_address.cpp
|
||||
session_pool.cpp
|
||||
session_table.cpp)
|
||||
session_table.cpp
|
||||
session_timer.cpp)
|
||||
target_include_directories(session_manager PUBLIC ${CMAKE_SOURCE_DIR}/deps/uthash)
|
||||
target_include_directories(session_manager PUBLIC ${CMAKE_SOURCE_DIR}/deps/timeout)
|
||||
target_include_directories(session_manager PUBLIC ${CMAKE_SOURCE_DIR}/src/packet)
|
||||
target_include_directories(session_manager PUBLIC ${CMAKE_SOURCE_DIR}/src/session)
|
||||
target_link_libraries(session_manager)
|
||||
target_link_libraries(session_manager timeout)
|
||||
|
||||
###############################################################################
|
||||
# gtest
|
||||
@@ -32,8 +34,13 @@ add_executable(gtest_session_table gtest_session_table.cpp)
|
||||
target_include_directories(gtest_session_table PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||
target_link_libraries(gtest_session_table session_manager gtest)
|
||||
|
||||
add_executable(gtest_session_timer gtest_session_timer.cpp)
|
||||
target_include_directories(gtest_session_timer PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||
target_link_libraries(gtest_session_timer session_manager gtest)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(gtest_session)
|
||||
gtest_discover_tests(gtest_session_address)
|
||||
gtest_discover_tests(gtest_session_pool)
|
||||
gtest_discover_tests(gtest_session_table)
|
||||
gtest_discover_tests(gtest_session_table)
|
||||
gtest_discover_tests(gtest_session_timer)
|
||||
160
src/session/gtest_session_timer.cpp
Normal file
160
src/session/gtest_session_timer.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "session_timer.h"
|
||||
#include "session_private.h"
|
||||
|
||||
static void session_expire(struct session *sess)
|
||||
{
|
||||
printf("=== session %lu expired ===\n", session_get_id(sess));
|
||||
}
|
||||
|
||||
TEST(SESSION_TIMER, ADD_DEL)
|
||||
{
|
||||
struct session sess;
|
||||
struct session_timer *timer = session_timer_create();
|
||||
EXPECT_TRUE(timer != NULL);
|
||||
|
||||
session_init(&sess);
|
||||
session_set_id(&sess, 1);
|
||||
session_set_expirecb(&sess, session_expire, 1000);
|
||||
|
||||
session_timer_add_session(timer, &sess);
|
||||
session_timer_del_session(timer, &sess);
|
||||
|
||||
session_timer_destroy(timer);
|
||||
}
|
||||
|
||||
TEST(SESSION_TIMER, EXPIRE)
|
||||
{
|
||||
struct session *sess = NULL;
|
||||
struct session sess1;
|
||||
struct session sess2;
|
||||
struct session sess3;
|
||||
struct session_timer *timer = session_timer_create();
|
||||
EXPECT_TRUE(timer != NULL);
|
||||
|
||||
session_init(&sess1);
|
||||
session_init(&sess2);
|
||||
session_init(&sess3);
|
||||
session_set_id(&sess1, 1);
|
||||
session_set_id(&sess2, 2);
|
||||
session_set_id(&sess3, 3);
|
||||
session_set_expirecb(&sess1, session_expire, 5);
|
||||
session_set_expirecb(&sess2, session_expire, 5);
|
||||
session_set_expirecb(&sess3, session_expire, 10);
|
||||
|
||||
session_timer_add_session(timer, &sess1);
|
||||
session_timer_add_session(timer, &sess2);
|
||||
session_timer_add_session(timer, &sess3);
|
||||
|
||||
for (uint64_t abs_current_ts = 0; abs_current_ts < 15; abs_current_ts++)
|
||||
{
|
||||
printf("current timestamp %lu\n", abs_current_ts);
|
||||
do
|
||||
{
|
||||
sess = session_timer_expire_session(timer, abs_current_ts);
|
||||
if (sess != NULL)
|
||||
{
|
||||
session_run_expirecb(sess);
|
||||
}
|
||||
} while (sess);
|
||||
}
|
||||
|
||||
session_timer_destroy(timer);
|
||||
}
|
||||
|
||||
TEST(SESSION_TIMER, BEFORE_EXPIRE_DEL)
|
||||
{
|
||||
struct session *sess = NULL;
|
||||
struct session sess1;
|
||||
struct session sess2;
|
||||
struct session sess3;
|
||||
struct session_timer *timer = session_timer_create();
|
||||
EXPECT_TRUE(timer != NULL);
|
||||
|
||||
session_init(&sess1);
|
||||
session_init(&sess2);
|
||||
session_init(&sess3);
|
||||
session_set_id(&sess1, 1);
|
||||
session_set_id(&sess2, 2);
|
||||
session_set_id(&sess3, 3);
|
||||
session_set_expirecb(&sess1, session_expire, 5);
|
||||
session_set_expirecb(&sess2, session_expire, 5);
|
||||
session_set_expirecb(&sess3, session_expire, 10);
|
||||
|
||||
session_timer_add_session(timer, &sess1);
|
||||
session_timer_add_session(timer, &sess2);
|
||||
session_timer_add_session(timer, &sess3);
|
||||
|
||||
for (uint64_t abs_current_ts = 0; abs_current_ts < 15; abs_current_ts++)
|
||||
{
|
||||
printf("current timestamp %lu\n", abs_current_ts);
|
||||
if (abs_current_ts == 2)
|
||||
{
|
||||
printf("delete timer 2\n");
|
||||
session_timer_del_session(timer, &sess2);
|
||||
}
|
||||
do
|
||||
{
|
||||
sess = session_timer_expire_session(timer, abs_current_ts);
|
||||
if (sess != NULL)
|
||||
{
|
||||
session_run_expirecb(sess);
|
||||
}
|
||||
} while (sess);
|
||||
}
|
||||
|
||||
session_timer_destroy(timer);
|
||||
}
|
||||
|
||||
TEST(SESSION_TIMER, BEFORE_EXPIRE_UPDATE)
|
||||
{
|
||||
struct session *sess = NULL;
|
||||
struct session sess1;
|
||||
struct session sess2;
|
||||
struct session sess3;
|
||||
struct session_timer *timer = session_timer_create();
|
||||
EXPECT_TRUE(timer != NULL);
|
||||
|
||||
session_init(&sess1);
|
||||
session_init(&sess2);
|
||||
session_init(&sess3);
|
||||
session_set_id(&sess1, 1);
|
||||
session_set_id(&sess2, 2);
|
||||
session_set_id(&sess3, 3);
|
||||
session_set_expirecb(&sess1, session_expire, 5);
|
||||
session_set_expirecb(&sess2, session_expire, 5);
|
||||
session_set_expirecb(&sess3, session_expire, 10);
|
||||
|
||||
session_timer_add_session(timer, &sess1);
|
||||
session_timer_add_session(timer, &sess2);
|
||||
session_timer_add_session(timer, &sess3);
|
||||
|
||||
for (uint64_t abs_current_ts = 0; abs_current_ts < 15; abs_current_ts++)
|
||||
{
|
||||
printf("current timestamp %lu\n", abs_current_ts);
|
||||
if (abs_current_ts == 2)
|
||||
{
|
||||
printf("update timer 2\n");
|
||||
session_timer_del_session(timer, &sess2);
|
||||
session_set_expirecb(&sess2, session_expire, 8);
|
||||
session_timer_add_session(timer, &sess2);
|
||||
}
|
||||
do
|
||||
{
|
||||
sess = session_timer_expire_session(timer, abs_current_ts);
|
||||
if (sess != NULL)
|
||||
{
|
||||
session_run_expirecb(sess);
|
||||
}
|
||||
} while (sess);
|
||||
}
|
||||
|
||||
session_timer_destroy(timer);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -184,11 +184,6 @@ void session_set_last_time(struct session *sess, uint64_t timestamp)
|
||||
sess->last_time = timestamp;
|
||||
}
|
||||
|
||||
void session_set_expire_time(struct session *sess, uint64_t timestamp)
|
||||
{
|
||||
sess->expire_time = timestamp;
|
||||
}
|
||||
|
||||
uint64_t session_get_create_time(struct session *sess)
|
||||
{
|
||||
return sess->create_time;
|
||||
@@ -199,11 +194,6 @@ uint64_t session_get_last_time(struct session *sess)
|
||||
return sess->last_time;
|
||||
}
|
||||
|
||||
uint64_t session_get_expire_time(struct session *sess)
|
||||
{
|
||||
return sess->expire_time;
|
||||
}
|
||||
|
||||
// session event
|
||||
bool session_push_event(struct session *sess, uint32_t event)
|
||||
{
|
||||
@@ -304,3 +294,34 @@ void session_free_ex_data(struct session *sess, uint8_t idx)
|
||||
|
||||
sess->ex_data[idx] = NULL;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* session expire
|
||||
******************************************************************************/
|
||||
|
||||
// session expire
|
||||
void session_set_expirecb(struct session *sess, session_expire_cb fn, uint64_t abs_expire_ts)
|
||||
{
|
||||
struct timeout *timeout = &sess->timeout;
|
||||
|
||||
timeout_init(timeout, TIMEOUT_ABS);
|
||||
timeout_setcb(timeout, fn, sess);
|
||||
sess->abs_expire_ts = abs_expire_ts;
|
||||
}
|
||||
|
||||
void session_del_expirecb(struct session *sess)
|
||||
{
|
||||
struct timeout *timeout = &sess->timeout;
|
||||
|
||||
timeout_init(timeout, 0);
|
||||
sess->abs_expire_ts = 0;
|
||||
}
|
||||
|
||||
void session_run_expirecb(struct session *sess)
|
||||
{
|
||||
struct timeout *timeout = &sess->timeout;
|
||||
if (timeout->callback.fn)
|
||||
{
|
||||
timeout->callback.fn(timeout->callback.arg);
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,17 @@ void *session_get0_ex_data(struct session *sess, uint8_t idx);
|
||||
*/
|
||||
void session_free_ex_data(struct session *sess, uint8_t idx);
|
||||
|
||||
/******************************************************************************
|
||||
* session expire
|
||||
******************************************************************************/
|
||||
|
||||
typedef void (*session_expire_cb)(struct session *sess);
|
||||
|
||||
// session timer
|
||||
void session_set_expirecb(struct session *sess, session_expire_cb fn, uint64_t abs_timeout_ts);
|
||||
void session_del_expirecb(struct session *sess);
|
||||
void session_run_expirecb(struct session *sess);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -14,6 +14,14 @@ extern "C"
|
||||
#include "session.h"
|
||||
#include "session_address.h"
|
||||
|
||||
#define TIMEOUT_CB_OVERRIDE
|
||||
struct timeout_cb
|
||||
{
|
||||
session_expire_cb fn;
|
||||
struct session *arg;
|
||||
};
|
||||
#include "timeout.h"
|
||||
|
||||
#define EX_DATA_MAX_COUNT 128
|
||||
#define SESSION_EVENT_QUEUE_SIZE 256
|
||||
|
||||
@@ -45,7 +53,6 @@ struct session
|
||||
// session timestamp
|
||||
uint64_t create_time;
|
||||
uint64_t last_time;
|
||||
uint64_t expire_time;
|
||||
|
||||
/******************************
|
||||
* Session Ev Queue Zone
|
||||
@@ -64,6 +71,8 @@ struct session
|
||||
******************************/
|
||||
|
||||
// session timer
|
||||
struct timeout timeout;
|
||||
uint64_t abs_expire_ts;
|
||||
|
||||
/******************************
|
||||
* Session Pool Zone
|
||||
|
||||
69
src/session/session_timer.cpp
Normal file
69
src/session/session_timer.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "session_timer.h"
|
||||
#include "session_private.h"
|
||||
|
||||
struct session_timer
|
||||
{
|
||||
struct timeouts *timeouts;
|
||||
};
|
||||
|
||||
struct session_timer *session_timer_create()
|
||||
{
|
||||
timeout_error_t err;
|
||||
struct session_timer *timer = (struct session_timer *)calloc(1, sizeof(struct session_timer));
|
||||
if (timer == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
timer->timeouts = timeouts_open(0, &err);
|
||||
if (timer->timeouts == NULL)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
return timer;
|
||||
|
||||
error:
|
||||
session_timer_destroy(timer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void session_timer_destroy(struct session_timer *timer)
|
||||
{
|
||||
if (timer)
|
||||
{
|
||||
if (timer->timeouts)
|
||||
{
|
||||
timeouts_close(timer->timeouts);
|
||||
}
|
||||
|
||||
free(timer);
|
||||
timer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void session_timer_add_session(struct session_timer *timer, struct session *sess)
|
||||
{
|
||||
struct timeout *timeout = &sess->timeout;
|
||||
timeouts_add(timer->timeouts, timeout, sess->abs_expire_ts);
|
||||
}
|
||||
|
||||
void session_timer_del_session(struct session_timer *timer, struct session *sess)
|
||||
{
|
||||
struct timeout *timeout = &sess->timeout;
|
||||
timeouts_del(timer->timeouts, timeout);
|
||||
}
|
||||
|
||||
struct session *session_timer_expire_session(struct session_timer *timer, uint64_t abs_current_ts)
|
||||
{
|
||||
timeouts_update(timer->timeouts, abs_current_ts);
|
||||
|
||||
struct timeout *timeout = timeouts_get(timer->timeouts);
|
||||
if (timeout == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct session *sess = (struct session *)timeout->callback.arg;
|
||||
return sess;
|
||||
}
|
||||
26
src/session/session_timer.h
Normal file
26
src/session/session_timer.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef _SESSION_TIMER_H
|
||||
#define _SESSION_TIMER_H
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "session.h"
|
||||
|
||||
struct session_timer;
|
||||
struct session_timer *session_timer_create();
|
||||
void session_timer_destroy(struct session_timer *timer);
|
||||
void session_timer_add_session(struct session_timer *timer, struct session *sess);
|
||||
void session_timer_del_session(struct session_timer *timer, struct session *sess);
|
||||
/*
|
||||
* return one session which timeout, or NULL if no session timeout.
|
||||
* if return session, the session will be removed from timer.
|
||||
*/
|
||||
struct session *session_timer_expire_session(struct session_timer *timer, uint64_t abs_current_ts);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user