Use microsecond resolution in timeouts
This commit is contained in:
parent
ab73580c23
commit
dab1565f31
67
ethermess.c
67
ethermess.c
|
@ -51,7 +51,7 @@ unsigned char broadcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
|||
unsigned char own_status = EMS_AVAILABLE;
|
||||
unsigned char own_nick[256];
|
||||
unsigned char own_nick_length = 0;
|
||||
time_t next_status_broadcast;
|
||||
struct timespec next_status_broadcast;
|
||||
|
||||
enum message_send_states {IDLE, QUEUED, SENDING};
|
||||
enum message_send_states own_message_send_state = IDLE;
|
||||
|
@ -111,12 +111,55 @@ unsigned char random_byte(void) {
|
|||
return randomness;
|
||||
}
|
||||
|
||||
time_t monotonic_time(void) {
|
||||
struct timespec ms_in_future(intmax_t ms) {
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
|
||||
err(1, "clock_gettime");
|
||||
}
|
||||
|
||||
// We can't really do anything to check for time_t overflow, because
|
||||
// there are no macros to test for its size, so let's just hope it
|
||||
// won't overflow
|
||||
ts.tv_sec += ms / 1000;
|
||||
#if LONG_MAX < 1999999999L
|
||||
#error This code does time arithmetic, and requires a long big enough to hold almost 2 seconds worth of nanoseconds
|
||||
#endif
|
||||
ts.tv_nsec += (ms % 1000) * 1000 * 1000;
|
||||
if (ts.tv_nsec >= 1000 * 1000 * 1000) {
|
||||
ts.tv_sec += -1;
|
||||
ts.tv_nsec -= 1000 * 1000 * 1000;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
int wait_ms_until(struct timespec then) {
|
||||
// This function basically returns the difference in ms between the
|
||||
// current time and the given time, clamped to [0, INT_MAX]
|
||||
//
|
||||
// That format works for poll(2), which will immediately exit after
|
||||
// checking status if timeout is 0, and otherwise wait the given
|
||||
// number of ms
|
||||
|
||||
struct timespec now;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
|
||||
err(1, "clock_gettime");
|
||||
}
|
||||
return now.tv_sec;
|
||||
|
||||
// Overflow not checked because fuck overflow checking in C
|
||||
// TODO: Check overflow
|
||||
intmax_t sec_diff = then.tv_sec - now.tv_sec;
|
||||
intmax_t ns_diff = then.tv_nsec - now.tv_nsec;
|
||||
intmax_t ms = sec_diff * 1000 + ns_diff / 1000 / 1000;
|
||||
|
||||
// Clamp
|
||||
if (ms > INT_MAX) {
|
||||
ms = INT_MAX;
|
||||
} else if (ms < 0) {
|
||||
ms = 0;
|
||||
}
|
||||
|
||||
return (int)ms;
|
||||
}
|
||||
|
||||
char hexify(int nybble) {
|
||||
|
@ -648,21 +691,13 @@ void eventloop(void) {
|
|||
}
|
||||
|
||||
// Figure out how many ms to wait
|
||||
int wait_ms;
|
||||
time_t now = monotonic_time();
|
||||
if (next_status_broadcast <= now) {
|
||||
int wait_ms = wait_ms_until(next_status_broadcast);
|
||||
if (wait_ms == 0) {
|
||||
// The time has come to send the status broadcast
|
||||
send_status(broadcast_mac);
|
||||
// Do next one in about 5 minutes
|
||||
next_status_broadcast = now + 5 * 60 + random_byte() / 64;
|
||||
} else {
|
||||
if (INT_MAX / 1000 >= next_status_broadcast - now) {
|
||||
// Wail until next status broadcast is due
|
||||
wait_ms = (next_status_broadcast - now) * 1000;
|
||||
} else {
|
||||
// Would overflow, wait INT_MAX ms
|
||||
wait_ms = INT_MAX;
|
||||
}
|
||||
next_status_broadcast = ms_in_future(5 * 60 * 1000 + 1000 * random_byte() / 64);
|
||||
wait_ms = wait_ms_until(next_status_broadcast);
|
||||
}
|
||||
|
||||
int ready = poll(pollfds, sizeof(pollfds) / sizeof(*pollfds), wait_ms);
|
||||
|
@ -767,7 +802,7 @@ int main(int argc, char **argv) {
|
|||
send_status(broadcast_mac);
|
||||
|
||||
// Schedule next broadcast of our status about 5 min in the future
|
||||
next_status_broadcast = monotonic_time() + 5 * 60 + random_byte() / 64;
|
||||
next_status_broadcast = ms_in_future(5 * 60 * 1000 + 1000 * random_byte() / 64);
|
||||
|
||||
// Request status from everyone, so that we can get an idea of who is on the network
|
||||
send_status_request(broadcast_mac);
|
||||
|
|
Loading…
Reference in New Issue