Merge branch 'clock-seconds-granularity' into master

This commit is contained in:
Daniel Eklöf 2020-09-24 16:01:25 +02:00
commit bd29bf765b
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 78 additions and 7 deletions

View file

@ -18,6 +18,8 @@
* YAML parsing error messages being replaced with a generic _“unknown
error”_.
* Memory leak when a YAML parsing error was encountered.
* clock: update every second when necessary
(https://codeberg.org/dnkl/yambar/issues/12).
### Security

View file

@ -4,7 +4,11 @@
#include <assert.h>
#include <poll.h>
#include <sys/time.h>
#define LOG_MODULE "clock"
#define LOG_ENABLE_DBG 0
#include "../log.h"
#include "../bar/bar.h"
#include "../config.h"
#include "../config-verify.h"
@ -12,6 +16,10 @@
struct private {
struct particle *label;
enum {
UPDATE_GRANULARITY_SECONDS,
UPDATE_GRANULARITY_MINUTES,
} update_granularity;
char *date_format;
char *time_format;
};
@ -55,20 +63,56 @@ content(struct module *mod)
static int
run(struct module *mod)
{
const struct private *m = mod->private;
const struct bar *bar = mod->bar;
bar->refresh(bar);
while (true) {
time_t now = time(NULL);
time_t now_no_secs = now / 60 * 60;
assert(now_no_secs % 60 == 0);
struct timespec _now;
clock_gettime(CLOCK_REALTIME, &_now);
time_t next_min = now_no_secs + 60;
time_t timeout = next_min - now;
assert(timeout >= 0 && timeout <= 60);
const struct timeval now = {
.tv_sec = _now.tv_sec,
.tv_usec = _now.tv_nsec / 1000,
};
int timeout_ms;
switch (m->update_granularity) {
case UPDATE_GRANULARITY_SECONDS: {
const struct timeval next_second = {
.tv_sec = now.tv_sec + 1,
.tv_usec = 0};
struct timeval _timeout;
timersub(&next_second, &now, &_timeout);
assert(_timeout.tv_sec == 0 ||
(_timeout.tv_sec == 1 && _timeout.tv_usec == 0));
timeout_ms = _timeout.tv_usec / 1000;
break;
}
case UPDATE_GRANULARITY_MINUTES: {
const struct timeval next_minute = {
.tv_sec = now.tv_sec / 60 * 60 + 60,
.tv_usec = 0,
};
struct timeval _timeout;
timersub(&next_minute, &now, &_timeout);
timeout_ms = _timeout.tv_sec * 1000 + _timeout.tv_usec / 1000;
}
}
/* Add 1ms to account for rounding errors */
timeout_ms++;
LOG_DBG("now: %lds %ldµs -> timeout: %dms",
now.tv_sec, now.tv_usec, timeout_ms);
struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}};
poll(fds, 1, timeout * 1000);
poll(fds, 1, timeout_ms);
if (fds[0].revents & POLLIN)
break;
@ -87,6 +131,31 @@ clock_new(struct particle *label, const char *date_format, const char *time_form
m->date_format = strdup(date_format);
m->time_format = strdup(time_format);
static const char *const seconds_formatters[] = {
"%c",
"%s",
"%S",
"%T",
"%r",
"%X",
};
m->update_granularity = UPDATE_GRANULARITY_MINUTES;
for (size_t i = 0;
i < sizeof(seconds_formatters) / sizeof(seconds_formatters[0]);
i++)
{
if (strstr(time_format, seconds_formatters[i]) != NULL) {
m->update_granularity = UPDATE_GRANULARITY_SECONDS;
break;
}
}
LOG_DBG("using %s update granularity",
(m->update_granularity == UPDATE_GRANULARITY_MINUTES
? "minutes" : "seconds"));
struct module *mod = module_common_new();
mod->private = m;
mod->run = &run;