aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2018-05-31 18:13:40 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2018-05-31 18:13:40 +0200
commita928399a67d0311fab9ec7a305c1790fc2470dc7 (patch)
treee426a9a524356eecbd4d54ccc68ddc092c82c232
parentfe2be43bce7b56ec0ee4ece18c4ba0ed7cc4ad94 (diff)
move to timespec WIPneels/monotonic_timers
-rw-r--r--include/osmocom/core/timer.h11
-rw-r--r--src/fsm.c6
-rw-r--r--src/select.c5
-rw-r--r--src/timer.c75
-rw-r--r--tests/gb/bssgp_fc_test.c25
-rw-r--r--tests/timer/timer_misc_test.c56
6 files changed, 94 insertions, 84 deletions
diff --git a/include/osmocom/core/timer.h b/include/osmocom/core/timer.h
index caf4c67..7b512db 100644
--- a/include/osmocom/core/timer.h
+++ b/include/osmocom/core/timer.h
@@ -43,6 +43,7 @@
#include <time.h>
#include <stdbool.h>
+#include <osmocom/core/defs.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/linuxrbtree.h>
@@ -55,7 +56,7 @@
struct osmo_timer_list {
struct rb_node node; /*!< rb-tree node header */
struct llist_head list; /*!< internal list header */
- struct timeval timeout; /*!< expiration time */
+ struct timespec timeout_at; /*!< expiration time */
unsigned int active : 1; /*!< is it active? */
void (*cb)(void*); /*!< call-back called at timeout */
@@ -78,11 +79,15 @@ int osmo_timer_pending(struct osmo_timer_list *timer);
int osmo_timer_remaining(const struct osmo_timer_list *timer,
const struct timeval *now,
- struct timeval *remaining);
+ struct timeval *remaining)
+ OSMO_DEPRECATED("using gettimeofday() for 'now' no longer works: changed to a monotonic clock.");
+
+int osmo_timer_remaining2(const struct osmo_timer_list *timer, struct timespec *remaining);
+
/*
* internal timer list management
*/
-struct timeval *osmo_timers_nearest(void);
+struct timespec *osmo_timers_nearest(void);
void osmo_timers_prepare(void);
int osmo_timers_update(void);
int osmo_timers_check(void);
diff --git a/src/fsm.c b/src/fsm.c
index ac53bca..042d953 100644
--- a/src/fsm.c
+++ b/src/fsm.c
@@ -436,7 +436,7 @@ static int state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
struct osmo_fsm *fsm = fi->fsm;
uint32_t old_state = fi->state;
const struct osmo_fsm_state *st = &fsm->states[fi->state];
- struct timeval remaining;
+ struct timespec remaining;
/* validate if new_state is a valid state */
if (!(st->out_state_mask & (1 << new_state))) {
@@ -454,10 +454,10 @@ static int state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
if (st->onleave)
st->onleave(fi, new_state);
- if (keep_timer && fi->timer.active && (osmo_timer_remaining(&fi->timer, NULL, &remaining) == 0))
+ if (keep_timer && fi->timer.active && (osmo_timer_remaining2(&fi->timer, &remaining) == 0))
LOGPFSMSRC(fi, file, line, "State change to %s (keeping T%d, %ld.%03lds remaining)\n",
osmo_fsm_state_name(fsm, new_state),
- fi->T, remaining.tv_sec, remaining.tv_usec / 1000);
+ fi->T, remaining.tv_sec, remaining.tv_nsec / 1000000);
else if (timeout_secs && !keep_timer)
LOGPFSMSRC(fi, file, line, "State change to %s (T%d, %lus)\n",
osmo_fsm_state_name(fsm, new_state),
diff --git a/src/select.c b/src/select.c
index 0b115c6..443d5e8 100644
--- a/src/select.c
+++ b/src/select.c
@@ -235,7 +235,7 @@ int osmo_select_main(int polling)
{
fd_set readset, writeset, exceptset;
int rc;
- struct timeval no_time = {0, 0};
+ struct timespec no_time = {0, 0};
FD_ZERO(&readset);
FD_ZERO(&writeset);
@@ -246,7 +246,8 @@ int osmo_select_main(int polling)
if (!polling)
osmo_timers_prepare();
- rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : osmo_timers_nearest());
+ rc = pselect(maxfd+1, &readset, &writeset, &exceptset,
+ polling ? &no_time : osmo_timers_nearest(), NULL);
if (rc < 0)
return 0;
diff --git a/src/timer.c b/src/timer.c
index 79c4225..4904948 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -39,22 +39,14 @@
#include <osmocom/core/timer_compat.h>
#include <osmocom/core/linuxlist.h>
-int get_time(struct timeval *now)
+static int osmo_timer_now(struct timespec *now)
{
- struct timespec ts;
-
- osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
- now = (struct timeval){
- .tv_sec = ts.ts_sec,
- .tv_usec = ts.ts_nsec / 1000,
- };
- if (ts.ts_nsec % 1000)
- return osmo_gettimeofday(&now, NULL);
+ return osmo_clock_gettime(CLOCK_MONOTONIC, now);
}
/* These store the amount of time that we wait until next timer expires. */
-static struct timeval nearest;
-static struct timeval *nearest_p;
+static struct timespec nearest;
+static struct timespec *nearest_p;
static struct rb_root timer_root = RB_ROOT;
@@ -69,7 +61,7 @@ static void __add_timer(struct osmo_timer_list *timer)
this = container_of(*new, struct osmo_timer_list, node);
parent = *new;
- if (timercmp(&timer->timeout, &this->timeout, <))
+ if (timespeccmp(&timer->timeout_at, &this->timeout_at, <))
new = &((*new)->rb_left);
else
new = &((*new)->rb_right);
@@ -115,12 +107,12 @@ void osmo_timer_add(struct osmo_timer_list *timer)
void
osmo_timer_schedule(struct osmo_timer_list *timer, int seconds, int microseconds)
{
- struct timeval current_time;
+ struct timespec current_time;
- get_time(&current_time);
- timer->timeout.tv_sec = seconds;
- timer->timeout.tv_usec = microseconds;
- timeradd(&timer->timeout, &current_time, &timer->timeout);
+ osmo_timer_now(&current_time);
+ timer->timeout_at.tv_sec = seconds;
+ timer->timeout_at.tv_nsec = microseconds * 1000;
+ timespecadd(&timer->timeout_at, &current_time, &timer->timeout_at);
osmo_timer_add(timer);
}
@@ -172,30 +164,35 @@ int osmo_timer_remaining(const struct osmo_timer_list *timer,
const struct timeval *now,
struct timeval *remaining)
{
- struct timeval current_time;
-
- if (!now)
- get_time(&current_time);
- else
- current_time = *now;
-
- timersub(&timer->timeout, &current_time, remaining);
+ struct timespec remaining_ts;
+ int rc = osmo_timer_remaining2(timer, &remaining_ts);
+ *remaining = (struct timeval){
+ .tv_sec = remaining_ts.tv_sec,
+ .tv_usec = remaining_ts.tv_nsec / 1000,
+ };
+ return rc;
+}
+int osmo_timer_remaining2(const struct osmo_timer_list *timer,
+ struct timespec *remaining)
+{
+ struct timespec current_time;
+ osmo_timer_now(&current_time);
+ timespecsub(&timer->timeout_at, &current_time, remaining);
if (remaining->tv_sec < 0)
return -1;
-
return 0;
}
/*! Determine time between now and the nearest timer
- * \returns pointer to timeval of nearest timer, NULL if there is none
+ * \returns pointer to timespec of nearest timer, NULL if there is none
*
* if we have a nearest time return the delta between the current
* time and the time of the nearest timer.
* If the nearest timer timed out return NULL and then we will
* dispatch everything after the select
*/
-struct timeval *osmo_timers_nearest(void)
+struct timespec *osmo_timers_nearest(void)
{
/* nearest_p is exactly what we need already: NULL if nothing is
* waiting, {0,0} if we must dispatch immediately, and the correct
@@ -203,14 +200,14 @@ struct timeval *osmo_timers_nearest(void)
return nearest_p;
}
-static void update_nearest(struct timeval *cand, struct timeval *current)
+static void update_nearest(struct timespec *cand, struct timespec *current)
{
if (cand->tv_sec != LONG_MAX) {
- if (timercmp(cand, current, >))
- timersub(cand, current, &nearest);
+ if (timespeccmp(cand, current, >))
+ timespecsub(cand, current, &nearest);
else {
/* loop again inmediately */
- timerclear(&nearest);
+ timespecclear(&nearest);
}
nearest_p = &nearest;
} else {
@@ -222,15 +219,15 @@ static void update_nearest(struct timeval *cand, struct timeval *current)
void osmo_timers_prepare(void)
{
struct rb_node *node;
- struct timeval current;
+ struct timespec current;
- get_time(&current);
+ osmo_timer_now(&current);
node = rb_first(&timer_root);
if (node) {
struct osmo_timer_list *this;
this = container_of(node, struct osmo_timer_list, node);
- update_nearest(&this->timeout, &current);
+ update_nearest(&this->timeout_at, &current);
} else {
nearest_p = NULL;
}
@@ -239,19 +236,19 @@ void osmo_timers_prepare(void)
/*! fire all timers... and remove them */
int osmo_timers_update(void)
{
- struct timeval current_time;
+ struct timespec current_time;
struct rb_node *node;
struct llist_head timer_eviction_list;
struct osmo_timer_list *this;
int work = 0;
- get_time(&current_time);
+ osmo_timer_now(&current_time);
INIT_LLIST_HEAD(&timer_eviction_list);
for (node = rb_first(&timer_root); node; node = rb_next(node)) {
this = container_of(node, struct osmo_timer_list, node);
- if (timercmp(&this->timeout, &current_time, >))
+ if (timespeccmp(&this->timeout_at, &current_time, >))
break;
llist_add(&this->list, &timer_eviction_list);
diff --git a/tests/gb/bssgp_fc_test.c b/tests/gb/bssgp_fc_test.c
index cc38777..1890d1c 100644
--- a/tests/gb/bssgp_fc_test.c
+++ b/tests/gb/bssgp_fc_test.c
@@ -13,21 +13,22 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/talloc.h>
+#include <osmocom/core/timer_compat.h>
#include <osmocom/gprs/gprs_bssgp.h>
static unsigned long in_ctr = 1;
-static struct timeval tv_start;
+static struct timespec ts_start;
void *ctx = NULL;
int get_centisec_diff(void)
{
- struct timeval tv;
- struct timeval now;
- osmo_gettimeofday(&now, NULL);
+ struct timespec ts;
+ struct timespec now;
+ osmo_clock_gettime(CLOCK_MONOTONIC, &now);
- timersub(&now, &tv_start, &tv);
+ timespecsub(&now, &ts_start, &ts);
- return tv.tv_sec * 100 + tv.tv_usec/10000;
+ return ts.tv_sec * 100 + ts.tv_nsec/10000000;
}
static int fc_out_cb(struct bssgp_flow_control *fc, struct msgb *msg,
@@ -74,17 +75,19 @@ static void test_fc(uint32_t bucket_size_max, uint32_t bucket_leak_rate,
{
struct bssgp_flow_control *fc = talloc_zero(ctx, struct bssgp_flow_control);
int i;
+ struct timespec *now;
+ osmo_clock_override_enable(CLOCK_MONOTONIC, true);
+ now = osmo_clock_override_gettimespec(CLOCK_MONOTONIC);
- osmo_gettimeofday_override_time = (struct timeval){
+ *now = (struct timespec){
.tv_sec = 1486385000,
- .tv_usec = 423423,
+ .tv_nsec = 423423423,
};
- osmo_gettimeofday_override = true;
bssgp_fc_init(fc, bucket_size_max, bucket_leak_rate, max_queue_depth,
fc_out_cb);
- osmo_gettimeofday(&tv_start, NULL);
+ osmo_clock_gettime(CLOCK_MONOTONIC, &ts_start);
/* Fill the queue with PDUs, possibly beyond the queue being full. If it is full, additional PDUs
* are discarded. */
@@ -96,7 +99,7 @@ static void test_fc(uint32_t bucket_size_max, uint32_t bucket_leak_rate,
}
while (1) {
- osmo_gettimeofday_override_add(0, 100000);
+ osmo_clock_override_add(CLOCK_MONOTONIC, 0, 100000000L);
osmo_timers_check();
osmo_timers_prepare();
diff --git a/tests/timer/timer_misc_test.c b/tests/timer/timer_misc_test.c
index 9e604b5..e31423b 100644
--- a/tests/timer/timer_misc_test.c
+++ b/tests/timer/timer_misc_test.c
@@ -25,42 +25,42 @@
#include <osmocom/core/timer.h>
struct timer_remaining_testcase {
- struct timeval now;
- struct timeval timeout;
+ struct timespec now;
+ struct timespec timeout;
int expect_rc;
- struct timeval expect_diff;
+ struct timespec expect_diff;
};
struct timer_remaining_testcase timer_remaining_data[] = {
{
- .now = { .tv_sec = 1000000, .tv_usec = 0 },
- .timeout = { .tv_sec = 1000123, .tv_usec = 1 },
+ .now = { .tv_sec = 1000000, .tv_nsec = 0 },
+ .timeout = { .tv_sec = 1000123, .tv_nsec = 1 },
.expect_rc = 0,
- .expect_diff = { .tv_sec = 123, .tv_usec = 1 },
+ .expect_diff = { .tv_sec = 123, .tv_nsec = 1 },
},
{
- .now = { .tv_sec = 1000000, .tv_usec = 0 },
- .timeout = { .tv_sec = 1000000, .tv_usec = 1 },
+ .now = { .tv_sec = 1000000, .tv_nsec = 0 },
+ .timeout = { .tv_sec = 1000000, .tv_nsec = 1 },
.expect_rc = 0,
- .expect_diff = { .tv_sec = 0, .tv_usec = 1 },
+ .expect_diff = { .tv_sec = 0, .tv_nsec = 1 },
},
{
- .now = { .tv_sec = 1000000, .tv_usec = 1 },
- .timeout = { .tv_sec = 1000000, .tv_usec = 0 },
+ .now = { .tv_sec = 1000000, .tv_nsec = 1 },
+ .timeout = { .tv_sec = 1000000, .tv_nsec = 0 },
.expect_rc = -1,
- .expect_diff = { .tv_sec = 0 - 1, .tv_usec = 999999 },
+ .expect_diff = { .tv_sec = 0 - 1, .tv_nsec = 999999999 },
},
{
- .now = { .tv_sec = 1000001, .tv_usec = 1 },
- .timeout = { .tv_sec = 1000000, .tv_usec = 0 },
+ .now = { .tv_sec = 1000001, .tv_nsec = 1 },
+ .timeout = { .tv_sec = 1000000, .tv_nsec = 0 },
.expect_rc = -1,
- .expect_diff = { .tv_sec = -1 - 1, .tv_usec = 999999 },
+ .expect_diff = { .tv_sec = -1 - 1, .tv_nsec = 999999999 },
},
{
- .now = { .tv_sec = 1000123, .tv_usec = 1 },
- .timeout = { .tv_sec = 1000000, .tv_usec = 0 },
+ .now = { .tv_sec = 1000123, .tv_nsec = 1 },
+ .timeout = { .tv_sec = 1000000, .tv_nsec = 0 },
.expect_rc = -1,
- .expect_diff = { .tv_sec = -123 - 1, .tv_usec = 999999 },
+ .expect_diff = { .tv_sec = -123 - 1, .tv_nsec = 999999999 },
},
};
@@ -68,24 +68,28 @@ void test_timer_remaining()
{
int i;
bool all_ok = true;
+ struct timespec *now;
printf("\n--- start: %s\n", __func__);
+ osmo_clock_override_enable(CLOCK_MONOTONIC, true);
+ now = osmo_clock_override_gettimespec(CLOCK_MONOTONIC);
for (i = 0; i < ARRAY_SIZE(timer_remaining_data); i++) {
struct timer_remaining_testcase *tc = &timer_remaining_data[i];
struct osmo_timer_list t = {
- .timeout = tc->timeout,
+ .timeout_at = tc->timeout,
.active = 1,
};
- struct timeval diff;
+ struct timespec diff;
int rc;
bool ok = true;
- rc = osmo_timer_remaining(&t, &tc->now, &diff);
+ *now = tc->now;
+ rc = osmo_timer_remaining2(&t, &diff);
printf("timeout:%ld.%06ld - now:%ld.%06ld = diff:%ld.%06ld; rc=%d\n",
- t.timeout.tv_sec, t.timeout.tv_usec,
- tc->now.tv_sec, tc->now.tv_usec,
- diff.tv_sec, diff.tv_usec,
+ t.timeout_at.tv_sec, t.timeout_at.tv_nsec,
+ tc->now.tv_sec, tc->now.tv_nsec,
+ diff.tv_sec, diff.tv_nsec,
rc);
if (rc != tc->expect_rc) {
@@ -93,9 +97,9 @@ void test_timer_remaining()
ok = false;
}
- if (diff.tv_sec != tc->expect_diff.tv_sec || diff.tv_usec != tc->expect_diff.tv_usec) {
+ if (diff.tv_sec != tc->expect_diff.tv_sec || diff.tv_nsec != tc->expect_diff.tv_nsec) {
printf(" ERROR: expected diff = %ld.%06ld\n",
- tc->expect_diff.tv_sec, tc->expect_diff.tv_usec);
+ tc->expect_diff.tv_sec, tc->expect_diff.tv_nsec);
ok = false;
}