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_library(timeout STATIC timeout.cpp timeout-bitops.cpp)
|
||||||
add_definitions(-fPIC)
|
target_include_directories(timeout PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||||
add_library(timeout STATIC timeout.c timeout-bitops.c)
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#include <intrin.h> /* _BitScanForward, _BitScanReverse */
|
#include <intrin.h> /* _BitScanForward, _BitScanReverse */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* First define ctz and clz functions; these are compiler-dependent if
|
/* First define ctz and clz functions; these are compiler-dependent if
|
||||||
@@ -54,14 +54,14 @@ static __inline int clz64(uint64_t val)
|
|||||||
#else
|
#else
|
||||||
static __inline int ctz64(uint64_t val)
|
static __inline int ctz64(uint64_t val)
|
||||||
{
|
{
|
||||||
uint32_t lo = (uint32_t) val;
|
uint32_t lo = (uint32_t)val;
|
||||||
uint32_t hi = (uint32_t) (val >> 32);
|
uint32_t hi = (uint32_t)(val >> 32);
|
||||||
return lo ? ctz32(lo) : 32 + ctz32(hi);
|
return lo ? ctz32(lo) : 32 + ctz32(hi);
|
||||||
}
|
}
|
||||||
static __inline int clz64(uint64_t val)
|
static __inline int clz64(uint64_t val)
|
||||||
{
|
{
|
||||||
uint32_t lo = (uint32_t) val;
|
uint32_t lo = (uint32_t)val;
|
||||||
uint32_t hi = (uint32_t) (val >> 32);
|
uint32_t hi = (uint32_t)(val >> 32);
|
||||||
return hi ? clz32(hi) : 32 + clz32(lo);
|
return hi ? clz32(hi) : 32 + clz32(lo);
|
||||||
}
|
}
|
||||||
#endif
|
#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. */
|
/* TODO: There are more clever ways to do this in the generic case. */
|
||||||
|
|
||||||
|
#define process_(one, cz_bits, bits) \
|
||||||
#define process_(one, cz_bits, bits) \
|
if (x < (one << (cz_bits - bits))) \
|
||||||
if (x < ( one << (cz_bits - bits))) { rv += bits; x <<= bits; }
|
{ \
|
||||||
|
rv += bits; \
|
||||||
|
x <<= bits; \
|
||||||
|
}
|
||||||
|
|
||||||
#define process64(bits) process_((UINT64_C(1)), 64, (bits))
|
#define process64(bits) process_((UINT64_C(1)), 64, (bits))
|
||||||
static inline int clz64(uint64_t x)
|
static inline int clz64(uint64_t x)
|
||||||
@@ -105,8 +108,12 @@ static inline int clz32(uint32_t x)
|
|||||||
#undef process_
|
#undef process_
|
||||||
#undef process32
|
#undef process32
|
||||||
#undef process64
|
#undef process64
|
||||||
#define process_(one, bits) \
|
#define process_(one, bits) \
|
||||||
if ((x & ((one << (bits))-1)) == 0) { rv += bits; x >>= bits; }
|
if ((x & ((one << (bits)) - 1)) == 0) \
|
||||||
|
{ \
|
||||||
|
rv += bits; \
|
||||||
|
x >>= bits; \
|
||||||
|
}
|
||||||
|
|
||||||
#define process64(bits) process_((UINT64_C(1)), bits)
|
#define process64(bits) process_((UINT64_C(1)), bits)
|
||||||
static inline int ctz64(uint64_t x)
|
static inline int ctz64(uint64_t x)
|
||||||
@@ -152,15 +159,15 @@ static uint64_t testcases[] = {
|
|||||||
100,
|
100,
|
||||||
385789752,
|
385789752,
|
||||||
82574,
|
82574,
|
||||||
(((uint64_t)1)<<63) + (((uint64_t)1)<<31) + 10101
|
(((uint64_t)1) << 63) + (((uint64_t)1) << 31) + 10101};
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
naive_clz(int bits, uint64_t v)
|
naive_clz(int bits, uint64_t v)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
uint64_t bit = ((uint64_t)1) << (bits-1);
|
uint64_t bit = ((uint64_t)1) << (bits - 1);
|
||||||
while (bit && 0 == (v & bit)) {
|
while (bit && 0 == (v & bit))
|
||||||
|
{
|
||||||
r++;
|
r++;
|
||||||
bit >>= 1;
|
bit >>= 1;
|
||||||
}
|
}
|
||||||
@@ -173,7 +180,8 @@ naive_ctz(int bits, uint64_t v)
|
|||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
uint64_t bit = 1;
|
uint64_t bit = 1;
|
||||||
while (bit && 0 == (v & bit)) {
|
while (bit && 0 == (v & bit))
|
||||||
|
{
|
||||||
r++;
|
r++;
|
||||||
bit <<= 1;
|
bit <<= 1;
|
||||||
if (r == bits)
|
if (r == bits)
|
||||||
@@ -186,46 +194,50 @@ naive_ctz(int bits, uint64_t v)
|
|||||||
static int
|
static int
|
||||||
check(uint64_t vv)
|
check(uint64_t vv)
|
||||||
{
|
{
|
||||||
uint32_t v32 = (uint32_t) vv;
|
uint32_t v32 = (uint32_t)vv;
|
||||||
|
|
||||||
if (vv == 0)
|
if (vv == 0)
|
||||||
return 1; /* c[tl]z64(0) is undefined. */
|
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));
|
printf("mismatch with ctz64: %d\n", ctz64(vv));
|
||||||
exit(1);
|
exit(1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (clz64(vv) != naive_clz(64, vv)) {
|
if (clz64(vv) != naive_clz(64, vv))
|
||||||
|
{
|
||||||
printf("mismatch with clz64: %d\n", clz64(vv));
|
printf("mismatch with clz64: %d\n", clz64(vv));
|
||||||
exit(1);
|
exit(1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v32 == 0)
|
if (v32 == 0)
|
||||||
return 1; /* c[lt]z(0) is undefined. */
|
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));
|
printf("mismatch with ctz32: %d\n", ctz32(v32));
|
||||||
exit(1);
|
exit(1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (clz32(v32) != naive_clz(32, v32)) {
|
if (clz32(v32) != naive_clz(32, v32))
|
||||||
|
{
|
||||||
printf("mismatch with clz32: %d\n", clz32(v32));
|
printf("mismatch with clz32: %d\n", clz32(v32));
|
||||||
exit(1);
|
exit(1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int main(int c, char **v)
|
||||||
main(int c, char **v)
|
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
const unsigned int n = sizeof(testcases)/sizeof(testcases[0]);
|
const unsigned int n = sizeof(testcases) / sizeof(testcases[0]);
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
for (i = 0; i <= 63; ++i) {
|
for (i = 0; i <= 63; ++i)
|
||||||
|
{
|
||||||
uint64_t x = 1 << i;
|
uint64_t x = 1 << i;
|
||||||
if (!check(x))
|
if (!check(x))
|
||||||
result = 1;
|
result = 1;
|
||||||
@@ -234,16 +246,19 @@ main(int c, char **v)
|
|||||||
result = 1;
|
result = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i)
|
||||||
if (! check(testcases[i]))
|
{
|
||||||
|
if (!check(testcases[i]))
|
||||||
result = 1;
|
result = 1;
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result)
|
||||||
|
{
|
||||||
puts("FAIL");
|
puts("FAIL");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
puts("OK");
|
puts("OK");
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif
|
#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.
|
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
* ==========================================================================
|
* ==========================================================================
|
||||||
*/
|
*/
|
||||||
#include <limits.h> /* CHAR_BIT */
|
#include <limits.h> /* CHAR_BIT */
|
||||||
|
|
||||||
#include <stddef.h> /* NULL */
|
#include <stddef.h> /* NULL */
|
||||||
#include <stdlib.h> /* malloc(3) free(3) */
|
#include <stdlib.h> /* malloc(3) free(3) */
|
||||||
#include <stdio.h> /* FILE fprintf(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) */
|
#include <sys/queue.h> /* TAILQ(3) */
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
#define reltime_t timeout_t /* "" */
|
#define reltime_t timeout_t /* "" */
|
||||||
|
|
||||||
#if !defined countof
|
#if !defined countof
|
||||||
#define countof(a) (sizeof (a) / sizeof *(a))
|
#define countof(a) (sizeof(a) / sizeof *(a))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined endof
|
#if !defined endof
|
||||||
@@ -66,32 +66,34 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined MIN
|
#if !defined MIN
|
||||||
#define MIN(a, b) (((a) < (b))? (a) : (b))
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined MAX
|
#if !defined MAX
|
||||||
#define MAX(a, b) (((a) > (b))? (a) : (b))
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined TAILQ_CONCAT
|
#if !defined TAILQ_CONCAT
|
||||||
#define TAILQ_CONCAT(head1, head2, field) do { \
|
#define TAILQ_CONCAT(head1, head2, field) \
|
||||||
if (!TAILQ_EMPTY(head2)) { \
|
do \
|
||||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
{ \
|
||||||
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
if (!TAILQ_EMPTY(head2)) \
|
||||||
(head1)->tqh_last = (head2)->tqh_last; \
|
{ \
|
||||||
TAILQ_INIT((head2)); \
|
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||||
} \
|
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
||||||
} while (0)
|
(head1)->tqh_last = (head2)->tqh_last; \
|
||||||
|
TAILQ_INIT((head2)); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined TAILQ_FOREACH_SAFE
|
#if !defined TAILQ_FOREACH_SAFE
|
||||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||||
for ((var) = TAILQ_FIRST(head); \
|
for ((var) = TAILQ_FIRST(head); \
|
||||||
(var) && ((tvar) = TAILQ_NEXT(var, field), 1); \
|
(var) && ((tvar) = TAILQ_NEXT(var, field), 1); \
|
||||||
(var) = (tvar))
|
(var) = (tvar))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* B I T M A N I P U L A T I O N R O U T I N E S
|
* 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 WHEEL_MASK (WHEEL_LEN - 1)
|
||||||
#define TIMEOUT_MAX ((TIMEOUT_C(1) << (WHEEL_BIT * WHEEL_NUM)) - 1)
|
#define TIMEOUT_MAX ((TIMEOUT_C(1) << (WHEEL_BIT * WHEEL_NUM)) - 1)
|
||||||
|
|
||||||
#include "timeout-bitops.c"
|
#include "timeout-bitops.cpp"
|
||||||
|
|
||||||
#if WHEEL_BIT == 6
|
#if WHEEL_BIT == 6
|
||||||
#define ctz(n) ctz64(n)
|
#define ctz(n) ctz64(n)
|
||||||
@@ -181,23 +183,22 @@ typedef uint8_t wheel_t;
|
|||||||
#error invalid WHEEL_BIT value
|
#error invalid WHEEL_BIT value
|
||||||
#endif
|
#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)))
|
if (!(c &= (sizeof v * CHAR_BIT - 1)))
|
||||||
return v;
|
return v;
|
||||||
|
|
||||||
return (v << c) | (v >> (sizeof v * CHAR_BIT - c));
|
return (v << c) | (v >> (sizeof v * CHAR_BIT - c));
|
||||||
} /* rotl() */
|
} /* 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)))
|
if (!(c &= (sizeof v * CHAR_BIT - 1)))
|
||||||
return v;
|
return v;
|
||||||
|
|
||||||
return (v >> c) | (v << (sizeof v * CHAR_BIT - c));
|
return (v >> c) | (v << (sizeof v * CHAR_BIT - c));
|
||||||
} /* rotr() */
|
} /* rotr() */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* T I M E R R O U T I N E S
|
* 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);
|
TAILQ_HEAD(timeout_list, timeout);
|
||||||
|
|
||||||
struct timeouts {
|
struct timeouts
|
||||||
|
{
|
||||||
struct timeout_list wheel[WHEEL_NUM][WHEEL_LEN], expired;
|
struct timeout_list wheel[WHEEL_NUM][WHEEL_LEN], expired;
|
||||||
|
|
||||||
wheel_t pending[WHEEL_NUM];
|
wheel_t pending[WHEEL_NUM];
|
||||||
@@ -214,33 +216,36 @@ struct timeouts {
|
|||||||
timeout_t hertz;
|
timeout_t hertz;
|
||||||
}; /* struct timeouts */
|
}; /* 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;
|
unsigned i, j;
|
||||||
|
|
||||||
for (i = 0; i < countof(T->wheel); i++) {
|
for (i = 0; i < countof(T->wheel); i++)
|
||||||
for (j = 0; j < countof(T->wheel[i]); j++) {
|
{
|
||||||
|
for (j = 0; j < countof(T->wheel[i]); j++)
|
||||||
|
{
|
||||||
TAILQ_INIT(&T->wheel[i][j]);
|
TAILQ_INIT(&T->wheel[i][j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TAILQ_INIT(&T->expired);
|
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->pending[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
T->curtime = 0;
|
T->curtime = 0;
|
||||||
T->hertz = (hz)? hz : TIMEOUT_mHZ;
|
T->hertz = (hz) ? hz : TIMEOUT_mHZ;
|
||||||
|
|
||||||
return T;
|
return T;
|
||||||
} /* timeouts_init() */
|
} /* 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;
|
struct timeouts *T;
|
||||||
|
|
||||||
if ((T = malloc(sizeof *T)))
|
if ((T = (struct timeouts *)malloc(sizeof *T)))
|
||||||
return timeouts_init(T, hz);
|
return timeouts_init(T, hz);
|
||||||
|
|
||||||
*error = errno;
|
*error = errno;
|
||||||
@@ -248,30 +253,33 @@ TIMEOUT_PUBLIC struct timeouts *timeouts_open(timeout_t hz, int *error) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
} /* timeouts_open() */
|
} /* timeouts_open() */
|
||||||
|
|
||||||
|
static void timeouts_reset(struct timeouts *T)
|
||||||
static void timeouts_reset(struct timeouts *T) {
|
{
|
||||||
struct timeout_list reset;
|
struct timeout_list reset;
|
||||||
struct timeout *to;
|
struct timeout *to;
|
||||||
unsigned i, j;
|
unsigned i, j;
|
||||||
|
|
||||||
TAILQ_INIT(&reset);
|
TAILQ_INIT(&reset);
|
||||||
|
|
||||||
for (i = 0; i < countof(T->wheel); i++) {
|
for (i = 0; i < countof(T->wheel); i++)
|
||||||
for (j = 0; j < countof(T->wheel[i]); j++) {
|
{
|
||||||
|
for (j = 0; j < countof(T->wheel[i]); j++)
|
||||||
|
{
|
||||||
TAILQ_CONCAT(&reset, &T->wheel[i][j], tqe);
|
TAILQ_CONCAT(&reset, &T->wheel[i][j], tqe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TAILQ_CONCAT(&reset, &T->expired, tqe);
|
TAILQ_CONCAT(&reset, &T->expired, tqe);
|
||||||
|
|
||||||
TAILQ_FOREACH(to, &reset, tqe) {
|
TAILQ_FOREACH(to, &reset, tqe)
|
||||||
|
{
|
||||||
to->pending = NULL;
|
to->pending = NULL;
|
||||||
TO_SET_TIMEOUTS(to, NULL);
|
TO_SET_TIMEOUTS(to, NULL);
|
||||||
}
|
}
|
||||||
} /* timeouts_reset() */
|
} /* 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
|
* NOTE: Delete installed timeouts so timeout_pending() and
|
||||||
* timeout_expired() worked as expected.
|
* timeout_expired() worked as expected.
|
||||||
@@ -281,17 +289,19 @@ TIMEOUT_PUBLIC void timeouts_close(struct timeouts *T) {
|
|||||||
free(T);
|
free(T);
|
||||||
} /* timeouts_close() */
|
} /* timeouts_close() */
|
||||||
|
|
||||||
|
TIMEOUT_PUBLIC timeout_t timeouts_hz(struct timeouts *T)
|
||||||
TIMEOUT_PUBLIC timeout_t timeouts_hz(struct timeouts *T) {
|
{
|
||||||
return T->hertz;
|
return T->hertz;
|
||||||
} /* timeouts_hz() */
|
} /* timeouts_hz() */
|
||||||
|
|
||||||
|
TIMEOUT_PUBLIC void timeouts_del(struct timeouts *T, struct timeout *to)
|
||||||
TIMEOUT_PUBLIC void timeouts_del(struct timeouts *T, struct timeout *to) {
|
{
|
||||||
if (to->pending) {
|
if (to->pending)
|
||||||
|
{
|
||||||
TAILQ_REMOVE(to->pending, to, tqe);
|
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];
|
ptrdiff_t index = to->pending - &T->wheel[0][0];
|
||||||
int wheel = index / WHEEL_LEN;
|
int wheel = index / WHEEL_LEN;
|
||||||
int slot = 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() */
|
} /* 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;
|
return to->expires - T->curtime;
|
||||||
} /* timeout_rem() */
|
} /* 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 */
|
/* must be called with timeout != 0, so fls input is nonzero */
|
||||||
return (fls(MIN(timeout, TIMEOUT_MAX)) - 1) / WHEEL_BIT;
|
return (fls(MIN(timeout, TIMEOUT_MAX)) - 1) / WHEEL_BIT;
|
||||||
} /* timeout_wheel() */
|
} /* 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);
|
return WHEEL_MASK & ((expires >> (wheel * WHEEL_BIT)) - !!wheel);
|
||||||
} /* timeout_slot() */
|
} /* 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;
|
timeout_t rem;
|
||||||
int wheel, slot;
|
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);
|
TO_SET_TIMEOUTS(to, T);
|
||||||
|
|
||||||
if (expires > T->curtime) {
|
if (expires > T->curtime)
|
||||||
|
{
|
||||||
rem = timeout_rem(T, to);
|
rem = timeout_rem(T, to);
|
||||||
|
|
||||||
/* rem is nonzero since:
|
/* 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);
|
TAILQ_INSERT_TAIL(to->pending, to, tqe);
|
||||||
|
|
||||||
T->pending[wheel] |= WHEEL_C(1) << slot;
|
T->pending[wheel] |= WHEEL_C(1) << slot;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
to->pending = &T->expired;
|
to->pending = &T->expired;
|
||||||
TAILQ_INSERT_TAIL(to->pending, to, tqe);
|
TAILQ_INSERT_TAIL(to->pending, to, tqe);
|
||||||
}
|
}
|
||||||
} /* timeouts_sched() */
|
} /* timeouts_sched() */
|
||||||
|
|
||||||
|
|
||||||
#ifndef TIMEOUT_DISABLE_INTERVALS
|
#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;
|
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
|
/* If we've missed the next firing of this timeout, reschedule
|
||||||
* it to occur at the next multiple of its interval after
|
* it to occur at the next multiple of its interval after
|
||||||
* the last time that it fired.
|
* the last time that it fired.
|
||||||
@@ -371,8 +385,8 @@ static void timeouts_readd(struct timeouts *T, struct timeout *to) {
|
|||||||
} /* timeouts_readd() */
|
} /* timeouts_readd() */
|
||||||
#endif
|
#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
|
#ifndef TIMEOUT_DISABLE_INTERVALS
|
||||||
if (to->flags & TIMEOUT_INT)
|
if (to->flags & TIMEOUT_INT)
|
||||||
to->interval = MAX(1, timeout);
|
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_sched(T, to, T->curtime + timeout);
|
||||||
} /* timeouts_add() */
|
} /* 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;
|
timeout_t elapsed = curtime - T->curtime;
|
||||||
struct timeout_list todo;
|
struct timeout_list todo;
|
||||||
int wheel;
|
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
|
* There's no avoiding looping over every wheel. It's best to keep
|
||||||
* WHEEL_NUM smallish.
|
* WHEEL_NUM smallish.
|
||||||
*/
|
*/
|
||||||
for (wheel = 0; wheel < WHEEL_NUM; wheel++) {
|
for (wheel = 0; wheel < WHEEL_NUM; wheel++)
|
||||||
|
{
|
||||||
wheel_t pending;
|
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
|
* If a wheel rolls over, force a tick of the next higher
|
||||||
* wheel.
|
* wheel.
|
||||||
*/
|
*/
|
||||||
if ((elapsed >> (wheel * WHEEL_BIT)) > WHEEL_MAX) {
|
if ((elapsed >> (wheel * WHEEL_BIT)) > WHEEL_MAX)
|
||||||
|
{
|
||||||
pending = (wheel_t)~WHEEL_C(0);
|
pending = (wheel_t)~WHEEL_C(0);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
wheel_t _elapsed = WHEEL_MASK & (elapsed >> (wheel * WHEEL_BIT));
|
wheel_t _elapsed = WHEEL_MASK & (elapsed >> (wheel * WHEEL_BIT));
|
||||||
int oslot, nslot;
|
int oslot, nslot;
|
||||||
|
|
||||||
@@ -432,7 +450,8 @@ TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) {
|
|||||||
pending |= WHEEL_C(1) << nslot;
|
pending |= WHEEL_C(1) << nslot;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (pending & T->pending[wheel]) {
|
while (pending & T->pending[wheel])
|
||||||
|
{
|
||||||
/* ctz input cannot be zero: loop condition. */
|
/* ctz input cannot be zero: loop condition. */
|
||||||
int slot = ctz(pending & T->pending[wheel]);
|
int slot = ctz(pending & T->pending[wheel]);
|
||||||
TAILQ_CONCAT(&todo, &T->wheel[wheel][slot], tqe);
|
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;
|
T->curtime = curtime;
|
||||||
|
|
||||||
while (!TAILQ_EMPTY(&todo)) {
|
while (!TAILQ_EMPTY(&todo))
|
||||||
|
{
|
||||||
struct timeout *to = TAILQ_FIRST(&todo);
|
struct timeout *to = TAILQ_FIRST(&todo);
|
||||||
|
|
||||||
TAILQ_REMOVE(&todo, to, tqe);
|
TAILQ_REMOVE(&todo, to, tqe);
|
||||||
@@ -460,29 +480,29 @@ TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) {
|
|||||||
return;
|
return;
|
||||||
} /* timeouts_update() */
|
} /* 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_update(T, T->curtime + elapsed);
|
||||||
} /* timeouts_step() */
|
} /* timeouts_step() */
|
||||||
|
|
||||||
|
TIMEOUT_PUBLIC bool timeouts_pending(struct timeouts *T)
|
||||||
TIMEOUT_PUBLIC bool timeouts_pending(struct timeouts *T) {
|
{
|
||||||
wheel_t pending = 0;
|
wheel_t pending = 0;
|
||||||
int wheel;
|
int wheel;
|
||||||
|
|
||||||
for (wheel = 0; wheel < WHEEL_NUM; wheel++) {
|
for (wheel = 0; wheel < WHEEL_NUM; wheel++)
|
||||||
|
{
|
||||||
pending |= T->pending[wheel];
|
pending |= T->pending[wheel];
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!pending;
|
return !!pending;
|
||||||
} /* timeouts_pending() */
|
} /* timeouts_pending() */
|
||||||
|
|
||||||
|
TIMEOUT_PUBLIC bool timeouts_expired(struct timeouts *T)
|
||||||
TIMEOUT_PUBLIC bool timeouts_expired(struct timeouts *T) {
|
{
|
||||||
return !TAILQ_EMPTY(&T->expired);
|
return !TAILQ_EMPTY(&T->expired);
|
||||||
} /* timeouts_expired() */
|
} /* timeouts_expired() */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the interval before needing to process any timeouts pending on
|
* Calculate the interval before needing to process any timeouts pending on
|
||||||
* any wheel.
|
* 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.
|
* 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 timeout = ~TIMEOUT_C(0), _timeout;
|
||||||
timeout_t relmask;
|
timeout_t relmask;
|
||||||
int wheel, slot;
|
int wheel, slot;
|
||||||
|
|
||||||
relmask = 0;
|
relmask = 0;
|
||||||
|
|
||||||
for (wheel = 0; wheel < WHEEL_NUM; wheel++) {
|
for (wheel = 0; wheel < WHEEL_NUM; wheel++)
|
||||||
if (T->pending[wheel]) {
|
{
|
||||||
|
if (T->pending[wheel])
|
||||||
|
{
|
||||||
slot = WHEEL_MASK & (T->curtime >> (wheel * WHEEL_BIT));
|
slot = WHEEL_MASK & (T->curtime >> (wheel * WHEEL_BIT));
|
||||||
|
|
||||||
/* ctz input cannot be zero: T->pending[wheel] is
|
/* 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);
|
timeout = MIN(_timeout, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
relmask <<= WHEEL_BIT;
|
relmask <<= WHEEL_BIT;
|
||||||
relmask |= WHEEL_MASK;
|
relmask |= WHEEL_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return timeout;
|
return timeout;
|
||||||
} /* timeouts_int() */
|
} /* timeouts_int() */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the interval our caller can wait before needing to process
|
* Calculate the interval our caller can wait before needing to process
|
||||||
* events.
|
* events.
|
||||||
*/
|
*/
|
||||||
TIMEOUT_PUBLIC timeout_t timeouts_timeout(struct timeouts *T) {
|
TIMEOUT_PUBLIC timeout_t timeouts_timeout(struct timeouts *T)
|
||||||
|
{
|
||||||
if (!TAILQ_EMPTY(&T->expired))
|
if (!TAILQ_EMPTY(&T->expired))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return timeouts_int(T);
|
return timeouts_int(T);
|
||||||
} /* timeouts_timeout() */
|
} /* timeouts_timeout() */
|
||||||
|
|
||||||
|
TIMEOUT_PUBLIC struct timeout *timeouts_get(struct timeouts *T)
|
||||||
TIMEOUT_PUBLIC struct timeout *timeouts_get(struct timeouts *T) {
|
{
|
||||||
if (!TAILQ_EMPTY(&T->expired)) {
|
if (!TAILQ_EMPTY(&T->expired))
|
||||||
|
{
|
||||||
struct timeout *to = TAILQ_FIRST(&T->expired);
|
struct timeout *to = TAILQ_FIRST(&T->expired);
|
||||||
|
|
||||||
TAILQ_REMOVE(&T->expired, to, tqe);
|
TAILQ_REMOVE(&T->expired, to, tqe);
|
||||||
@@ -555,23 +579,28 @@ TIMEOUT_PUBLIC struct timeout *timeouts_get(struct timeouts *T) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
return to;
|
return to;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} /* timeouts_get() */
|
} /* timeouts_get() */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use dumb looping to locate the earliest timeout pending on the wheel so
|
* Use dumb looping to locate the earliest timeout pending on the wheel so
|
||||||
* our invariant assertions can check the result of our optimized code.
|
* 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;
|
struct timeout *to, *min = NULL;
|
||||||
unsigned i, j;
|
unsigned i, j;
|
||||||
|
|
||||||
for (i = 0; i < countof(T->wheel); i++) {
|
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 (j = 0; j < countof(T->wheel[i]); j++)
|
||||||
|
{
|
||||||
|
TAILQ_FOREACH(to, &T->wheel[i][j], tqe)
|
||||||
|
{
|
||||||
if (!min || to->expires < min->expires)
|
if (!min || to->expires < min->expires)
|
||||||
min = to;
|
min = to;
|
||||||
}
|
}
|
||||||
@@ -581,28 +610,34 @@ static struct timeout *timeouts_min(struct timeouts *T) {
|
|||||||
return min;
|
return min;
|
||||||
} /* timeouts_min() */
|
} /* timeouts_min() */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check some basic algorithm invariants. If these invariants fail then
|
* Check some basic algorithm invariants. If these invariants fail then
|
||||||
* something is definitely broken.
|
* something is definitely broken.
|
||||||
*/
|
*/
|
||||||
#define report(...) do { \
|
#define report(...) \
|
||||||
if ((fp)) \
|
do \
|
||||||
fprintf(fp, __VA_ARGS__); \
|
{ \
|
||||||
} while (0)
|
if ((fp)) \
|
||||||
|
fprintf(fp, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define check(expr, ...) do { \
|
#define check(expr, ...) \
|
||||||
if (!(expr)) { \
|
do \
|
||||||
report(__VA_ARGS__); \
|
{ \
|
||||||
return 0; \
|
if (!(expr)) \
|
||||||
} \
|
{ \
|
||||||
} while (0)
|
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;
|
timeout_t timeout;
|
||||||
struct timeout *to;
|
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);
|
check(to->expires > T->curtime, "missed timeout (expires:%" TIMEOUT_PRIu " <= curtime:%" TIMEOUT_PRIu ")\n", to->expires, T->curtime);
|
||||||
|
|
||||||
timeout = timeouts_int(T);
|
timeout = timeouts_int(T);
|
||||||
@@ -610,7 +645,9 @@ TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *T, FILE *fp) {
|
|||||||
|
|
||||||
timeout = timeouts_timeout(T);
|
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);
|
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);
|
timeout = timeouts_timeout(T);
|
||||||
|
|
||||||
if (!TAILQ_EMPTY(&T->expired))
|
if (!TAILQ_EMPTY(&T->expired))
|
||||||
@@ -622,49 +659,65 @@ TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *T, FILE *fp) {
|
|||||||
return 1;
|
return 1;
|
||||||
} /* timeouts_check() */
|
} /* timeouts_check() */
|
||||||
|
|
||||||
|
#define ENTER \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
static const int pc0 = __LINE__; \
|
||||||
|
switch (pc0 + it->pc) \
|
||||||
|
{ \
|
||||||
|
case __LINE__: \
|
||||||
|
(void)0
|
||||||
|
|
||||||
#define ENTER \
|
#define SAVE_AND_DO(do_statement) \
|
||||||
do { \
|
do \
|
||||||
static const int pc0 = __LINE__; \
|
{ \
|
||||||
switch (pc0 + it->pc) { \
|
it->pc = __LINE__ - pc0; \
|
||||||
case __LINE__: (void)0
|
do_statement; \
|
||||||
|
case __LINE__: \
|
||||||
#define SAVE_AND_DO(do_statement) \
|
(void)0; \
|
||||||
do { \
|
|
||||||
it->pc = __LINE__ - pc0; \
|
|
||||||
do_statement; \
|
|
||||||
case __LINE__: (void)0; \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define YIELD(rv) \
|
#define YIELD(rv) \
|
||||||
SAVE_AND_DO(return (rv))
|
SAVE_AND_DO(return (rv))
|
||||||
|
|
||||||
#define LEAVE \
|
#define LEAVE \
|
||||||
SAVE_AND_DO(break); \
|
SAVE_AND_DO(break); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} \
|
||||||
|
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;
|
struct timeout *to;
|
||||||
|
|
||||||
ENTER;
|
ENTER;
|
||||||
|
|
||||||
if (it->flags & TIMEOUTS_EXPIRED) {
|
if (it->flags & TIMEOUTS_EXPIRED)
|
||||||
if (it->flags & TIMEOUTS_CLEAR) {
|
{
|
||||||
while ((to = timeouts_get(T))) {
|
if (it->flags & TIMEOUTS_CLEAR)
|
||||||
|
{
|
||||||
|
while ((to = timeouts_get(T)))
|
||||||
|
{
|
||||||
YIELD(to);
|
YIELD(to);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
TAILQ_FOREACH_SAFE(to, &T->expired, tqe, it->to) {
|
else
|
||||||
|
{
|
||||||
|
TAILQ_FOREACH_SAFE(to, &T->expired, tqe, it->to)
|
||||||
|
{
|
||||||
YIELD(to);
|
YIELD(to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it->flags & TIMEOUTS_PENDING) {
|
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++) {
|
for (it->i = 0; it->i < countof(T->wheel); it->i++)
|
||||||
TAILQ_FOREACH_SAFE(to, &T->wheel[it->i][it->j], tqe, it->to) {
|
{
|
||||||
|
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);
|
YIELD(to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -681,13 +734,13 @@ TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *T, struct timeouts
|
|||||||
#undef SAVE_AND_DO
|
#undef SAVE_AND_DO
|
||||||
#undef ENTER
|
#undef ENTER
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* T I M E O U T R O U T I N E S
|
* 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);
|
memset(to, 0, sizeof *to);
|
||||||
|
|
||||||
to->flags = flags;
|
to->flags = flags;
|
||||||
@@ -695,50 +748,49 @@ TIMEOUT_PUBLIC struct timeout *timeout_init(struct timeout *to, int flags) {
|
|||||||
return to;
|
return to;
|
||||||
} /* timeout_init() */
|
} /* timeout_init() */
|
||||||
|
|
||||||
|
|
||||||
#ifndef TIMEOUT_DISABLE_RELATIVE_ACCESS
|
#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;
|
return to->pending && to->pending != &to->timeouts->expired;
|
||||||
} /* timeout_pending() */
|
} /* 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;
|
return to->pending && to->pending == &to->timeouts->expired;
|
||||||
} /* timeout_expired() */
|
} /* timeout_expired() */
|
||||||
|
|
||||||
|
TIMEOUT_PUBLIC void timeout_del(struct timeout *to)
|
||||||
TIMEOUT_PUBLIC void timeout_del(struct timeout *to) {
|
{
|
||||||
timeouts_del(to->timeouts, to);
|
timeouts_del(to->timeouts, to);
|
||||||
} /* timeout_del() */
|
} /* timeout_del() */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* V E R S I O N I N T E R F A C E S
|
* 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;
|
return TIMEOUT_VERSION;
|
||||||
} /* timeout_version() */
|
} /* timeout_version() */
|
||||||
|
|
||||||
|
TIMEOUT_PUBLIC const char *timeout_vendor(void)
|
||||||
TIMEOUT_PUBLIC const char *timeout_vendor(void) {
|
{
|
||||||
return TIMEOUT_VENDOR;
|
return TIMEOUT_VENDOR;
|
||||||
} /* timeout_version() */
|
} /* timeout_version() */
|
||||||
|
|
||||||
|
TIMEOUT_PUBLIC int timeout_v_rel(void)
|
||||||
TIMEOUT_PUBLIC int timeout_v_rel(void) {
|
{
|
||||||
return TIMEOUT_V_REL;
|
return TIMEOUT_V_REL;
|
||||||
} /* timeout_version() */
|
} /* timeout_version() */
|
||||||
|
|
||||||
|
TIMEOUT_PUBLIC int timeout_v_abi(void)
|
||||||
TIMEOUT_PUBLIC int timeout_v_abi(void) {
|
{
|
||||||
return TIMEOUT_V_ABI;
|
return TIMEOUT_V_ABI;
|
||||||
} /* timeout_version() */
|
} /* timeout_version() */
|
||||||
|
|
||||||
|
TIMEOUT_PUBLIC int timeout_v_api(void)
|
||||||
TIMEOUT_PUBLIC int timeout_v_api(void) {
|
{
|
||||||
return TIMEOUT_V_API;
|
return TIMEOUT_V_API;
|
||||||
} /* timeout_version() */
|
} /* timeout_version() */
|
||||||
|
|
||||||
67
deps/timeout/timeout.h
vendored
67
deps/timeout/timeout.h
vendored
@@ -26,13 +26,12 @@
|
|||||||
#ifndef TIMEOUT_H
|
#ifndef TIMEOUT_H
|
||||||
#define TIMEOUT_H
|
#define TIMEOUT_H
|
||||||
|
|
||||||
#include <stdbool.h> /* bool */
|
#include <stdbool.h> /* bool */
|
||||||
#include <stdio.h> /* FILE */
|
#include <stdio.h> /* FILE */
|
||||||
|
|
||||||
#include <inttypes.h> /* PRIu64 PRIx64 PRIX64 uint64_t */
|
#include <inttypes.h> /* PRIu64 PRIx64 PRIX64 uint64_t */
|
||||||
|
|
||||||
#include <sys/queue.h> /* TAILQ(3) */
|
|
||||||
|
|
||||||
|
#include <sys/queue.h> /* TAILQ(3) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* V E R S I O N I N T E R F A C E S
|
* V E R S I O N I N T E R F A C E S
|
||||||
@@ -44,7 +43,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TIMEOUT_VERSION TIMEOUT_V_REL
|
#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_REL 0x20160226
|
||||||
#define TIMEOUT_V_ABI 0x20160224
|
#define TIMEOUT_V_ABI 0x20160224
|
||||||
@@ -60,7 +59,6 @@ TIMEOUT_PUBLIC int timeout_v_abi(void);
|
|||||||
|
|
||||||
TIMEOUT_PUBLIC int timeout_v_api(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
|
* 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 */
|
#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
|
* 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
|
#ifndef TIMEOUT_CB_OVERRIDE
|
||||||
struct timeout_cb {
|
struct timeout_cb
|
||||||
|
{
|
||||||
void (*fn)();
|
void (*fn)();
|
||||||
void *arg;
|
void *arg;
|
||||||
}; /* struct timeout_cb */
|
}; /* struct timeout_cb */
|
||||||
@@ -105,14 +103,20 @@ struct timeout_cb {
|
|||||||
#endif
|
#endif
|
||||||
#define TIMEOUT_ABS 0x02 /* treat timeout values as absolute */
|
#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 { \
|
#define timeout_setcb(to, _fn, _arg) \
|
||||||
(to)->callback.fn = (fn); \
|
do \
|
||||||
(to)->callback.arg = (arg); \
|
{ \
|
||||||
} while (0)
|
(to)->callback.fn = (_fn); \
|
||||||
|
(to)->callback.arg = (_arg); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
struct timeout {
|
struct timeout
|
||||||
|
{
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
timeout_t expires;
|
timeout_t expires;
|
||||||
@@ -121,7 +125,8 @@ struct timeout {
|
|||||||
struct timeout_list *pending;
|
struct timeout_list *pending;
|
||||||
/* timeout list if pending on wheel or expiry queue */
|
/* timeout list if pending on wheel or expiry queue */
|
||||||
|
|
||||||
TAILQ_ENTRY(timeout) tqe;
|
TAILQ_ENTRY(timeout)
|
||||||
|
tqe;
|
||||||
/* entry member for struct timeout_list lists */
|
/* entry member for struct timeout_list lists */
|
||||||
|
|
||||||
#ifndef TIMEOUT_DISABLE_CALLBACKS
|
#ifndef TIMEOUT_DISABLE_CALLBACKS
|
||||||
@@ -140,14 +145,13 @@ struct timeout {
|
|||||||
#endif
|
#endif
|
||||||
}; /* struct timeout */
|
}; /* struct timeout */
|
||||||
|
|
||||||
|
|
||||||
TIMEOUT_PUBLIC struct timeout *timeout_init(struct timeout *, int);
|
TIMEOUT_PUBLIC struct timeout *timeout_init(struct timeout *, int);
|
||||||
/* initialize timeout structure (same as TIMEOUT_INITIALIZER) */
|
/* initialize timeout structure (same as TIMEOUT_INITIALIZER) */
|
||||||
|
|
||||||
#ifndef TIMEOUT_DISABLE_RELATIVE_ACCESS
|
#ifndef TIMEOUT_DISABLE_RELATIVE_ACCESS
|
||||||
TIMEOUT_PUBLIC bool timeout_pending(struct timeout *);
|
TIMEOUT_PUBLIC bool timeout_pending(struct timeout *);
|
||||||
/* true if on timing wheel, false otherwise */
|
/* true if on timing wheel, false otherwise */
|
||||||
|
|
||||||
TIMEOUT_PUBLIC bool timeout_expired(struct timeout *);
|
TIMEOUT_PUBLIC bool timeout_expired(struct timeout *);
|
||||||
/* true if on expired queue, false otherwise */
|
/* 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_PENDING 0x10
|
||||||
#define TIMEOUTS_EXPIRED 0x20
|
#define TIMEOUTS_EXPIRED 0x20
|
||||||
#define TIMEOUTS_ALL (TIMEOUTS_PENDING|TIMEOUTS_EXPIRED)
|
#define TIMEOUTS_ALL (TIMEOUTS_PENDING | TIMEOUTS_EXPIRED)
|
||||||
#define TIMEOUTS_CLEAR 0x40
|
#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 { \
|
#define TIMEOUTS_IT_INIT(cur, _flags) \
|
||||||
(cur)->flags = (_flags); \
|
do \
|
||||||
(cur)->pc = 0; \
|
{ \
|
||||||
} while (0)
|
(cur)->flags = (_flags); \
|
||||||
|
(cur)->pc = 0; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
struct timeouts_it {
|
struct timeouts_it
|
||||||
|
{
|
||||||
int flags;
|
int flags;
|
||||||
unsigned pc, i, j;
|
unsigned pc, i, j;
|
||||||
struct timeout *to;
|
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.
|
* could invalidate cursor state and trigger a use-after-free.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define TIMEOUTS_FOREACH(var, T, flags) \
|
#define TIMEOUTS_FOREACH(var, T, flags) \
|
||||||
struct timeouts_it _it = TIMEOUTS_IT_INITIALIZER((flags)); \
|
struct timeouts_it _it = TIMEOUTS_IT_INITIALIZER((flags)); \
|
||||||
while (((var) = timeouts_next((T), &_it)))
|
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
|
* 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.cpp
|
||||||
session_address.cpp
|
session_address.cpp
|
||||||
session_pool.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/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/packet)
|
||||||
target_include_directories(session_manager PUBLIC ${CMAKE_SOURCE_DIR}/src/session)
|
target_include_directories(session_manager PUBLIC ${CMAKE_SOURCE_DIR}/src/session)
|
||||||
target_link_libraries(session_manager)
|
target_link_libraries(session_manager timeout)
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# gtest
|
# 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_include_directories(gtest_session_table PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||||
target_link_libraries(gtest_session_table session_manager gtest)
|
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)
|
include(GoogleTest)
|
||||||
gtest_discover_tests(gtest_session)
|
gtest_discover_tests(gtest_session)
|
||||||
gtest_discover_tests(gtest_session_address)
|
gtest_discover_tests(gtest_session_address)
|
||||||
gtest_discover_tests(gtest_session_pool)
|
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;
|
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)
|
uint64_t session_get_create_time(struct session *sess)
|
||||||
{
|
{
|
||||||
return sess->create_time;
|
return sess->create_time;
|
||||||
@@ -199,11 +194,6 @@ uint64_t session_get_last_time(struct session *sess)
|
|||||||
return sess->last_time;
|
return sess->last_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t session_get_expire_time(struct session *sess)
|
|
||||||
{
|
|
||||||
return sess->expire_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
// session event
|
// session event
|
||||||
bool session_push_event(struct session *sess, uint32_t 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;
|
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);
|
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
|
#ifdef __cpluscplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ extern "C"
|
|||||||
#include "session.h"
|
#include "session.h"
|
||||||
#include "session_address.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 EX_DATA_MAX_COUNT 128
|
||||||
#define SESSION_EVENT_QUEUE_SIZE 256
|
#define SESSION_EVENT_QUEUE_SIZE 256
|
||||||
|
|
||||||
@@ -45,7 +53,6 @@ struct session
|
|||||||
// session timestamp
|
// session timestamp
|
||||||
uint64_t create_time;
|
uint64_t create_time;
|
||||||
uint64_t last_time;
|
uint64_t last_time;
|
||||||
uint64_t expire_time;
|
|
||||||
|
|
||||||
/******************************
|
/******************************
|
||||||
* Session Ev Queue Zone
|
* Session Ev Queue Zone
|
||||||
@@ -64,6 +71,8 @@ struct session
|
|||||||
******************************/
|
******************************/
|
||||||
|
|
||||||
// session timer
|
// session timer
|
||||||
|
struct timeout timeout;
|
||||||
|
uint64_t abs_expire_ts;
|
||||||
|
|
||||||
/******************************
|
/******************************
|
||||||
* Session Pool Zone
|
* 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